> ## Documentation Index
> Fetch the complete documentation index at: https://docs.topify.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Actions

> Manage AI-generated recommendations for improving your brand visibility in AI search results.

Actions are AI-generated recommendations for improving your brand's visibility in AI search results. There are four action categories: `on_page_seo` (advisory SEO changes), `new_content` (new articles with full write workflow), `content_update` (page edit suggestions), and `forum_engagement` (Reddit reply drafts).

## List actions

```
GET /projects/{project_id}/actions
```

Returns all actions for a project, optionally filtered by status or group.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |

### Query parameters

| Param | Type | Default | Description |
| - | - | - | - |
| `status` | string | -- | Filter by status (`suggested`, `accepted`, `in_progress`, `completed`, `ignored`) |
| `group` | string | -- | Filter by group name |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions?status=suggested" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.get(f"/projects/{project_id}/actions", params={"status": "suggested"})
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions?status=suggested`, { headers });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": [
    {
      "id": "a1b2c3d4-...",
      "priority": "high",
      "title": "Add structured data to pricing page",
      "description": "Adding FAQ schema markup to your pricing page will help AI models extract and cite your pricing details.",
      "category": "on_page_seo",
      "effort": "quick-win",
      "expected_impact_min": 5,
      "expected_impact_max": 15,
      "status": "suggested",
      "targets": [
        { "type": "url", "value": "https://example.com/pricing" }
      ],
      "execution": {
        "type": "manual",
        "prompt": null,
        "skill": null,
        "params": null
      },
      "group": "Technical SEO",
      "depends_on": [],
      "created_at": "2026-04-01T12:00:00Z",
      "updated_at": "2026-04-01T12:00:00Z"
    }
  ]
}
```

### ActionItem fields

| Field | Type | Nullable | Description |
| - | - | - | - |
| `id` | string (UUID) | No | Action ID |
| `priority` | string | No | `critical`, `high`, `medium`, or `low` |
| `title` | string | No | Short action title |
| `description` | string | No | Detailed explanation of the recommendation |
| `category` | string | No | `on_page_seo`, `new_content`, `content_update`, or `forum_engagement` |
| `effort` | string | Yes | `quick-win`, `moderate`, or `major` |
| `expected_impact_min` | number | Yes | Minimum estimated visibility impact (percentage points) |
| `expected_impact_max` | number | Yes | Maximum estimated visibility impact (percentage points) |
| `status` | string | No | `suggested`, `accepted`, `in_progress`, `completed`, or `ignored` |
| `targets` | object\[] | No | Array of targets (see below) |
| `execution` | object | No | Execution configuration (see below) |
| `group` | string | Yes | Logical grouping name |
| `depends_on` | string\[] | No | IDs of actions this action depends on |
| `created_at` | string | No | ISO 8601 timestamp |
| `updated_at` | string | No | ISO 8601 timestamp |

### Target object

| Field | Type | Description |
| - | - | - |
| `type` | string | `url`, `keyword`, `page_type`, or `domain` |
| `value` | string | The target value |

### Execution object

| Field | Type | Nullable | Description |
| - | - | - | - |
| `type` | string | No | `prompt`, `publishable_content`, `forum_reply`, or `manual` |
| `prompt` | string | Yes | LLM prompt used for execution |
| `skill` | string | Yes | Agent skill identifier |
| `params` | object | Yes | Additional execution parameters |

***

## Get single action

```
GET /projects/{project_id}/actions/{action_id}
```

Returns a single action by ID.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |
| `action_id` | string (UUID) | The action ID |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.get(f"/projects/{project_id}/actions/{action_id}")
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}`, { headers });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "id": "a1b2c3d4-...",
    "priority": "high",
    "title": "Add structured data to pricing page",
    "description": "Adding FAQ schema markup to your pricing page will help AI models extract and cite your pricing details.",
    "category": "on_page_seo",
    "effort": "quick-win",
    "expected_impact_min": 5,
    "expected_impact_max": 15,
    "status": "suggested",
    "targets": [
      { "type": "url", "value": "https://example.com/pricing" }
    ],
    "execution": {
      "type": "manual",
      "prompt": null,
      "skill": null,
      "params": null
    },
    "group": "Technical SEO",
    "depends_on": [],
    "created_at": "2026-04-01T12:00:00Z",
    "updated_at": "2026-04-01T12:00:00Z"
  }
}
```

### Error responses

| Status | Cause |
| - | - |
| `404` | Action not found in this project |

***

## Create action

```
POST /projects/{project_id}/actions
```

Create a new action manually.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |

### Request body

| Field | Type | Required | Description |
| - | - | - | - |
| `title` | string | Yes | Short action title |
| `description` | string | Yes | Detailed explanation |
| `category` | string | Yes | `on_page_seo`, `new_content`, `content_update`, or `forum_engagement` |
| `priority` | string | Yes | `critical`, `high`, `medium`, or `low` |
| `execution` | object | Yes | `{type, prompt?, skill?}` |
| `targets` | object\[] | No | Array of `{type, value}` targets |
| `effort` | string | No | `quick-win`, `moderate`, or `major` |
| `expected_impact_min` | number | No | Minimum estimated impact |
| `expected_impact_max` | number | No | Maximum estimated impact |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions" \
      -H "X-API-Key: tk_live_..." \
      -H "Content-Type: application/json" \
      -d '{
        "title": "Write a comparison article",
        "description": "Create an article comparing your product with top competitors for the keyword \"best project management tools\".",
        "category": "new_content",
        "priority": "high",
        "execution": {"type": "publishable_content", "skill": "write_article"},
        "targets": [{"type": "keyword", "value": "best project management tools"}],
        "effort": "major",
        "expected_impact_min": 10,
        "expected_impact_max": 25
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions", json={
        "title": "Write a comparison article",
        "description": "Create an article comparing your product with top competitors.",
        "category": "new_content",
        "priority": "high",
        "execution": {"type": "publishable_content", "skill": "write_article"},
        "targets": [{"type": "keyword", "value": "best project management tools"}],
    })
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions`, {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({
        title: "Write a comparison article",
        description: "Create an article comparing your product with top competitors.",
        category: "new_content",
        priority: "high",
        execution: { type: "publishable_content", skill: "write_article" },
        targets: [{ type: "keyword", value: "best project management tools" }],
      }),
    });
    ```
  </Tab>
</Tabs>

### Response

Returns the created action (same shape as [get single action](#get-single-action)) with status `suggested`.

### Error responses

| Status | Cause |
| - | - |
| `400` | Missing required fields or invalid category/priority/execution type |

***

## Enrich action

```
POST /projects/{project_id}/actions/enrich
```

Sends partial action data to the LLM and returns enriched fields (improved title, description, targets, execution config).

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |

### Request body

| Field | Type | Required | Description |
| - | - | - | - |
| `action_type` | string | Yes | `on_page_seo`, `new_content`, `content_update`, or `forum_engagement` |
| `title` | string | No | Draft title |
| `description` | string | No | Draft description |
| `target_url` | string | No | Target URL for the action |
| `keywords` | string\[] | No | Related keywords |
| `instructions` | string | No | Free-form instructions for the LLM |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/enrich" \
      -H "X-API-Key: tk_live_..." \
      -H "Content-Type: application/json" \
      -d '{
        "action_type": "new_content",
        "title": "Comparison article",
        "keywords": ["best project management tools"]
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions/enrich", json={
        "action_type": "new_content",
        "title": "Comparison article",
        "keywords": ["best project management tools"],
    })
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/enrich`, {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({
        action_type: "new_content",
        title: "Comparison article",
        keywords: ["best project management tools"],
      }),
    });
    ```
  </Tab>
</Tabs>

### Response

Returns LLM-enriched action fields (title, description, targets, execution, effort, expected impact).

### Error responses

| Status | Cause |
| - | - |
| `400` | Missing `action_type` or invalid value |

***

## Transition status

```
PATCH /projects/{project_id}/actions/{action_id}/{action}
```

Transition an action to a new status. The `action` path parameter determines the transition.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |
| `action_id` | string (UUID) | The action ID |
| `action` | string | One of: `accept`, `start`, `complete`, `ignore`, `reopen` |

### Request body (ignore only)

| Field | Type | Required | Description |
| - | - | - | - |
| `reason` | string | No | Reason for ignoring |
| `feedback` | string | No | Additional feedback |

### State machine

```
suggested --> accepted --> in_progress --> completed
    |                                        ^
    +--> ignored ---(reopen)---> accepted ---+
```

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X PATCH "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/accept" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.patch(f"/projects/{project_id}/actions/{action_id}/accept")
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/accept`, {
      method: "PATCH",
      headers,
    });
    ```
  </Tab>
</Tabs>

### Response

Returns the updated action with the new status.

### Error responses

| Status | Cause |
| - | - |
| `400` | Invalid transition (e.g., completing a `suggested` action) |
| `404` | Action not found |

***

## Batch transition

```
POST /projects/{project_id}/actions/batch-transition
```

Transition multiple actions at once.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |

### Request body

| Field | Type | Required | Description |
| - | - | - | - |
| `ids` | string\[] | Yes | Array of action IDs |
| `action` | string | Yes | `accept`, `start`, `complete`, `ignore`, or `reopen` |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/batch-transition" \
      -H "X-API-Key: tk_live_..." \
      -H "Content-Type: application/json" \
      -d '{
        "ids": ["a1b2c3d4-...", "e5f6g7h8-..."],
        "action": "accept"
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions/batch-transition", json={
        "ids": ["a1b2c3d4-...", "e5f6g7h8-..."],
        "action": "accept",
    })
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/batch-transition`, {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({
        ids: ["a1b2c3d4-...", "e5f6g7h8-..."],
        action: "accept",
      }),
    });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "succeeded": 2,
    "failed": 0,
    "total": 2
  }
}
```

### Error responses

| Status | Cause |
| - | - |
| `400` | Empty `ids` array or invalid `action` |

***

## Recommend actions

```
POST /projects/{project_id}/actions/recommend
```

Triggers AI-powered action recommendation generation as a background task. The AI analyzes your project data and generates a set of recommended actions.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/recommend" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions/recommend")
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/recommend`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "task_id": "f1e2d3c4-..."
  }
}
```

<Note>
  Use the [check recommendation task status](#check-recommendation-task-status) endpoint to poll for completion.
</Note>

***

## Check recommendation task status

```
GET /projects/{project_id}/actions/tasks/{task_id}
```

Check the status of a background recommendation task.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |
| `task_id` | string (UUID) | The task ID returned by the recommend endpoint |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/tasks/{task_id}" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.get(f"/projects/{project_id}/actions/tasks/{task_id}")
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/tasks/${taskId}`, { headers });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "status": "completed",
    "item_count": 12,
    "error": null
  }
}
```

### Task status values

| Status | Description |
| - | - |
| `running` | Task is still in progress |
| `completed` | Recommendations generated successfully |
| `failed` | Task encountered an error (see `error` field) |

***

## Enrich content

```
POST /projects/{project_id}/actions/{action_id}/enrich-content
```

For `content_update` actions. Scrapes the target page via Firecrawl, then generates SEO edit suggestions via LLM. Returns an array of specific edits to improve AI visibility.

<Note>
  This endpoint may take 10--20 seconds to respond as it scrapes and analyzes the target page.
</Note>

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |
| `action_id` | string (UUID) | The action ID (must be a `content_update` action) |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/enrich-content" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions/{action_id}/enrich-content")
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/enrich-content`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": [
    {
      "section": "Introduction paragraph",
      "type": "replace",
      "before": "We offer project management software.",
      "after": "We offer AI-powered project management software trusted by 10,000+ teams worldwide.",
      "signal": "authority",
      "reason": "Adding specificity and social proof helps AI models identify your brand as a credible source."
    },
    {
      "section": "FAQ section",
      "type": "insert",
      "before": null,
      "after": "<h2>Frequently Asked Questions</h2>...",
      "signal": "structured_data",
      "reason": "FAQ sections are heavily cited by AI models when answering user questions."
    }
  ]
}
```

### Edit object fields

| Field | Type | Nullable | Description |
| - | - | - | - |
| `section` | string | No | The page section being edited |
| `type` | string | No | `replace`, `insert`, or `delete` |
| `before` | string | Yes | Original text (null for `insert`) |
| `after` | string | Yes | Replacement text (null for `delete`) |
| `signal` | string | No | The SEO/GEO signal being addressed |
| `reason` | string | No | Explanation of why this edit improves visibility |

### Error responses

| Status | Cause |
| - | - |
| `400` | Action is not a `content_update` action or has no target URL |
| `404` | Action not found |

***

## Enrich forum

```
POST /projects/{project_id}/actions/{action_id}/enrich-forum
```

For `forum_engagement` actions. Regenerates a Reddit comment draft tailored to the target thread.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |
| `action_id` | string (UUID) | The action ID (must be a `forum_engagement` action) |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/enrich-forum" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions/{action_id}/enrich-forum")
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/enrich-forum`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "comment": "I've been using Acme for about six months now and it's been solid for our team...",
    "comment_word_count": 87,
    "thread_title": "What project management tool do you use?",
    "thread_url": "https://www.reddit.com/r/productivity/comments/..."
  }
}
```

### Error responses

| Status | Cause |
| - | - |
| `400` | Action is not a `forum_engagement` action |
| `404` | Action not found |

***

## Execute action

```
POST /projects/{project_id}/actions/{action_id}/execute
```

Starts the execution workflow for a `new_content` action with `publishable_content` execution type. This triggers article generation with human-in-the-loop approval checkpoints (outline, draft, final). Progress is delivered via [webhooks](/api-reference/webhooks).

<Warning>
  Only works for actions with `execution.type: "publishable_content"`. You must have a webhook registered for `action.checkpoint` events to receive approval prompts.
</Warning>

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |
| `action_id` | string (UUID) | The action ID |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/execute" \
      -H "X-API-Key: tk_live_..."
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions/{action_id}/execute")
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/execute`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### Response (202 Accepted)

```json theme={null}
{
  "success": true,
  "data": {
    "workflow_id": "w1x2y3z4-...",
    "status": "started"
  }
}
```

### Error responses

| Status | Cause |
| - | - |
| `400` | Action is not a `publishable_content` type or is not in `accepted`/`in_progress` status |
| `404` | Action not found |

***

## Respond to checkpoint

```
POST /projects/{project_id}/actions/{action_id}/execute/respond
```

Respond to an approval checkpoint in an active execution workflow. Called after receiving an `action.checkpoint` webhook event.

### Path parameters

| Param | Type | Description |
| - | - | - |
| `project_id` | string (UUID) | The project ID |
| `action_id` | string (UUID) | The action ID |

### Request body

| Field | Type | Required | Description |
| - | - | - | - |
| `workflow_id` | string (UUID) | Yes | The workflow ID from the checkpoint event |
| `decision` | string | Yes | `approve`, `edit`, `regenerate`, or `reject` |
| `edited_content` | string | No | Modified content (required when `decision` is `edit`) |
| `feedback` | string | No | Instructions for regeneration (used when `decision` is `regenerate`) |

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/execute/respond" \
      -H "X-API-Key: tk_live_..." \
      -H "Content-Type: application/json" \
      -d '{
        "workflow_id": "w1x2y3z4-...",
        "decision": "approve"
      }'
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    resp = client.post(f"/projects/{project_id}/actions/{action_id}/execute/respond", json={
        "workflow_id": "w1x2y3z4-...",
        "decision": "approve",
    })
    ```
  </Tab>

  <Tab title="Node.js (server-side)">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/execute/respond`, {
      method: "POST",
      headers: { ...headers, "Content-Type": "application/json" },
      body: JSON.stringify({
        workflow_id: "w1x2y3z4-...",
        decision: "approve",
      }),
    });
    ```
  </Tab>
</Tabs>

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "status": "continuing"
  }
}
```

### Error responses

| Status | Cause |
| - | - |
| `400` | Invalid decision, missing `workflow_id`, or `edited_content` required but not provided |
| `404` | Action or workflow not found |
| `409` | Workflow is not currently waiting at a checkpoint |

***

## Get action state

```http theme={null}
GET /projects/{project_id}/actions/{action_id}/state
```

Returns an agent-facing lifecycle snapshot without changing the action. The `next_actions` array contains ready-to-use HTTP instructions for the next valid transitions or checkpoint decisions.

```bash theme={null}
curl "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/state" \
  -H "X-API-Key: tk_live_..."
```

### Response

```json theme={null}
{
  "success": true,
  "data": {
    "action_id": "a1b2c3d4-...",
    "status": "in_progress",
    "lifecycle": "awaiting_decision",
    "current_checkpoint": "article_review",
    "workflow_id": "w1x2y3z4-...",
    "workflow_status": "pending",
    "ready_artifacts": ["research", "outline", "article"],
    "next_actions": [
      {
        "name": "approve",
        "label": "Approve and finalize",
        "http": {
          "method": "POST",
          "path": "/api/public/v1/projects/{project_id}/actions/{action_id}/execute/respond",
          "body": { "workflow_id": "w1x2y3z4-...", "decision": "approve" }
        }
      }
    ]
  }
}
```

Repeated polling is safe. A service request cannot use an action ID or task ID from a different project.

***

## List action artifacts

```http theme={null}
GET /projects/{project_id}/actions/{action_id}/artifacts
```

Lists artifact names that are ready to fetch for an action.

| Action type | Possible artifact names |
| - | - |
| Forum engagement | `thread`, `comment` |
| On-page SEO or content update | `edits` |
| Article workflow | `research`, `outline`, `article` |

```json theme={null}
{
  "success": true,
  "data": {
    "artifacts": ["research", "outline"]
  }
}
```

***

## Get action artifact

```http theme={null}
GET /projects/{project_id}/actions/{action_id}/artifacts/{name}
```

Returns one named artifact. The `article` artifact is a publish kit containing the article body, slug, frontmatter, SEO metadata, JSON-LD, and publishing instructions.

```bash theme={null}
curl "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/artifacts/article" \
  -H "X-API-Key: tk_live_..."
```

### Error responses

| Status | Code | Cause |
| - | - | - |
| `400` | `INVALID_ARTIFACT` | The artifact name does not apply to this action type |
| `404` | `NOT_FOUND` | The action does not exist in this project |
| `409` | `NOT_READY` | The artifact is valid but the workflow has not reached the required checkpoint |

***

## Store discarded edit

```http theme={null}
POST /projects/{project_id}/actions/{action_id}/discard-edit
```

Stores an in-progress draft in recovery history without advancing or cancelling the workflow. This is a recoverable draft operation, not prompt deletion.

### Request body

| Field | Type | Required | Description |
| - | - | - | - |
| `workflow_id` | string | Yes | Active workflow ID |
| `edited_content` | string | Yes | Non-empty draft content to retain |
| `checkpoint` | string | No | Checkpoint associated with the draft |

```bash theme={null}
curl -X POST "https://topify-customer-api-production.up.railway.app/api/public/v1/projects/{project_id}/actions/{action_id}/discard-edit" \
  -H "X-API-Key: tk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_id": "w1x2y3z4-...",
    "edited_content": "Draft article markdown",
    "checkpoint": "article_review"
  }'
```

The response returns `discarded_edits`, most recent last. A workflow retains at most 20 entries.

***

## List discarded edits

```http theme={null}
GET /projects/{project_id}/actions/{action_id}/discarded-edits
```

Returns the current workflow's recoverable draft history. This endpoint is read-only.

```json theme={null}
{
  "success": true,
  "data": {
    "discarded_edits": [
      {
        "content": "Draft article markdown",
        "checkpoint": "article_review",
        "timestamp": "2026-07-13T12:00:00.000Z"
      }
    ]
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.