> ## 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.

# 操作

> 管理由 AI 生成的建议，用于提升您的品牌在 AI 搜索结果中的可见度。

操作是 AI 生成的建议，用于提升您的品牌在 AI 搜索结果中的可见度。共有四种操作类别：`on_page_seo`（建议性 SEO 修改）、`new_content`（带完整撰写流程的新文章）、`content_update`（页面编辑建议）和 `forum_engagement`（Reddit 回复草稿）。

## 列出操作

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

返回项目的所有操作，可选按状态或分组筛选。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |

### 查询参数

| 参数       | 类型     | 默认值 | 描述                                                                |
| -------- | ------ | --- | ----------------------------------------------------------------- |
| `status` | string | --  | 按状态筛选（`suggested`、`accepted`、`in_progress`、`completed`、`ignored`） |
| `group`  | string | --  | 按分组名称筛选                                                           |

<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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions?status=suggested`, { headers });
    ```
  </Tab>
</Tabs>

### 响应

```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 字段

| 字段                    | 类型            | 可空  | 描述                                                                |
| --------------------- | ------------- | --- | ----------------------------------------------------------------- |
| `id`                  | string (UUID) | No  | 操作 ID                                                             |
| `priority`            | string        | No  | `critical`、`high`、`medium` 或 `low`                                |
| `title`               | string        | No  | 操作的简短标题                                                           |
| `description`         | string        | No  | 建议的详细说明                                                           |
| `category`            | string        | No  | `on_page_seo`、`new_content`、`content_update` 或 `forum_engagement` |
| `effort`              | string        | Yes | `quick-win`、`moderate` 或 `major`                                  |
| `expected_impact_min` | number        | Yes | 预估的最低可见度影响（百分点）                                                   |
| `expected_impact_max` | number        | Yes | 预估的最高可见度影响（百分点）                                                   |
| `status`              | string        | No  | `suggested`、`accepted`、`in_progress`、`completed` 或 `ignored`      |
| `targets`             | object\[]     | No  | 目标数组（见下文）                                                         |
| `execution`           | object        | No  | 执行配置（见下文）                                                         |
| `group`               | string        | Yes | 逻辑分组名称                                                            |
| `depends_on`          | string\[]     | No  | 此操作所依赖的操作 ID                                                      |
| `created_at`          | string        | No  | ISO 8601 创建时间                                                     |
| `updated_at`          | string        | No  | ISO 8601 更新时间                                                     |

### Target 对象

| 字段      | 类型     | 描述                                     |
| ------- | ------ | -------------------------------------- |
| `type`  | string | `url`、`keyword`、`page_type` 或 `domain` |
| `value` | string | 目标值                                    |

### Execution 对象

| 字段       | 类型     | 可空  | 描述                                                      |
| -------- | ------ | --- | ------------------------------------------------------- |
| `type`   | string | No  | `prompt`、`publishable_content`、`forum_reply` 或 `manual` |
| `prompt` | string | Yes | 用于执行的 LLM 提示                                            |
| `skill`  | string | Yes | 智能体技能标识                                                 |
| `params` | object | Yes | 额外的执行参数                                                 |

***

## 获取单个操作

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

按 ID 返回单个操作。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |
| `action_id`  | string (UUID) | 操作 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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}`, { headers });
    ```
  </Tab>
</Tabs>

### 响应

```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"
  }
}
```

### 错误响应

| 状态    | 原因         |
| ----- | ---------- |
| `404` | 在此项目中未找到操作 |

***

## 创建操作

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

手动创建一个新操作。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |

### 请求体

| 字段                    | 类型        | 必填  | 描述                                                                |
| --------------------- | --------- | --- | ----------------------------------------------------------------- |
| `title`               | string    | Yes | 操作的简短标题                                                           |
| `description`         | string    | Yes | 详细说明                                                              |
| `category`            | string    | Yes | `on_page_seo`、`new_content`、`content_update` 或 `forum_engagement` |
| `priority`            | string    | Yes | `critical`、`high`、`medium` 或 `low`                                |
| `execution`           | object    | Yes | `{type, prompt?, skill?}`                                         |
| `targets`             | object\[] | No  | `{type, value}` 目标数组                                              |
| `effort`              | string    | No  | `quick-win`、`moderate` 或 `major`                                  |
| `expected_impact_min` | number    | No  | 预估的最低影响                                                           |
| `expected_impact_max` | number    | No  | 预估的最高影响                                                           |

<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（服务端）">
    ```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>

### 响应

返回创建的操作（与 [获取单个操作](#get-single-action) 形状相同），状态为 `suggested`。

### 错误响应

| 状态    | 原因                                        |
| ----- | ----------------------------------------- |
| `400` | 缺少必填字段，或 category/priority/execution 类型无效 |
| `403` | API 密钥具有只读权限                              |

***

## 增强操作

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

将不完整的操作数据发送给 LLM 并返回增强后的字段（改进的标题、描述、目标、执行配置）。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |

### 请求体

| 字段             | 类型        | 必填  | 描述                                                                |
| -------------- | --------- | --- | ----------------------------------------------------------------- |
| `action_type`  | string    | Yes | `on_page_seo`、`new_content`、`content_update` 或 `forum_engagement` |
| `title`        | string    | No  | 草稿标题                                                              |
| `description`  | string    | No  | 草稿描述                                                              |
| `target_url`   | string    | No  | 此操作的目标 URL                                                        |
| `keywords`     | string\[] | No  | 相关关键词                                                             |
| `instructions` | string    | No  | 给 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（服务端）">
    ```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>

### 响应

返回经 LLM 增强后的操作字段（标题、描述、目标、执行配置、工作量、预估影响）。

### 错误响应

| 状态    | 原因                    |
| ----- | --------------------- |
| `400` | 缺少 `action_type` 或值无效 |

***

## 状态切换

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

将操作切换到新状态。`action` 路径参数决定切换方式。

### 路径参数

| 参数           | 类型            | 描述                                                 |
| ------------ | ------------- | -------------------------------------------------- |
| `project_id` | string (UUID) | 项目 ID                                              |
| `action_id`  | string (UUID) | 操作 ID                                              |
| `action`     | string        | 取值之一：`accept`、`start`、`complete`、`ignore`、`reopen` |

### 请求体（仅 ignore）

| 字段         | 类型     | 必填 | 描述    |
| ---------- | ------ | -- | ----- |
| `reason`   | string | No | 忽略的原因 |
| `feedback` | string | No | 额外的反馈 |

### 状态机

```
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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/accept`, {
      method: "PATCH",
      headers,
    });
    ```
  </Tab>
</Tabs>

### 响应

返回切换至新状态后的操作。

### 错误响应

| 状态    | 原因                              |
| ----- | ------------------------------- |
| `400` | 无效的状态切换（例如完成 `suggested` 状态的操作） |
| `403` | API 密钥具有只读权限                    |
| `404` | 未找到操作                           |

***

## 批量切换状态

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

一次切换多个操作的状态。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |

### 请求体

| 字段       | 类型        | 必填  | 描述                                              |
| -------- | --------- | --- | ----------------------------------------------- |
| `ids`    | string\[] | Yes | 操作 ID 数组                                        |
| `action` | string    | Yes | `accept`、`start`、`complete`、`ignore` 或 `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（服务端）">
    ```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>

### 响应

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

### 错误响应

| 状态    | 原因                      |
| ----- | ----------------------- |
| `400` | `ids` 数组为空或 `action` 无效 |
| `403` | API 密钥具有只读权限            |

***

## 推荐操作

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

将基于 AI 的操作推荐生成作为后台任务触发。AI 会分析您的项目数据并生成一组推荐操作。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/recommend`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### 响应

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

<Note>
  使用 [查询推荐任务状态](#check-recommendation-task-status) 端点轮询完成情况。
</Note>

***

## 查询推荐任务状态

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

查询后台推荐任务的状态。

### 路径参数

| 参数           | 类型            | 描述           |
| ------------ | ------------- | ------------ |
| `project_id` | string (UUID) | 项目 ID        |
| `task_id`    | string (UUID) | 推荐端点返回的任务 ID |

<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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/tasks/${taskId}`, { headers });
    ```
  </Tab>
</Tabs>

### 响应

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

### 任务状态值

| 状态          | 描述                     |
| ----------- | ---------------------- |
| `running`   | 任务仍在进行中                |
| `completed` | 推荐生成成功                 |
| `failed`    | 任务遇到错误（请查看 `error` 字段） |

***

## 增强内容

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

适用于 `content_update` 操作。通过 Firecrawl 抓取目标页面，然后通过 LLM 生成 SEO 编辑建议。返回一组用于提升 AI 可见度的具体编辑。

<Note>
  此端点可能需要 10--20 秒才能响应，因为它需要抓取并分析目标页面。
</Note>

### 路径参数

| 参数           | 类型            | 描述                             |
| ------------ | ------------- | ------------------------------ |
| `project_id` | string (UUID) | 项目 ID                          |
| `action_id`  | string (UUID) | 操作 ID（必须是 `content_update` 操作） |

<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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/enrich-content`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### 响应

```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 对象字段

| 字段        | 类型     | 可空  | 描述                            |
| --------- | ------ | --- | ----------------------------- |
| `section` | string | No  | 被编辑的页面区域                      |
| `type`    | string | No  | `replace`、`insert` 或 `delete` |
| `before`  | string | Yes | 原始文本（`insert` 时为 null）        |
| `after`   | string | Yes | 替换文本（`delete` 时为 null）        |
| `signal`  | string | No  | 针对的 SEO/GEO 信号                |
| `reason`  | string | No  | 此编辑为何能提升可见度的说明                |

### 错误响应

| 状态    | 原因                                 |
| ----- | ---------------------------------- |
| `400` | 操作不是 `content_update` 类型，或没有目标 URL |
| `404` | 未找到操作                              |

***

## 增强论坛

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

适用于 `forum_engagement` 操作。重新生成针对目标主题帖量身定制的 Reddit 评论草稿。

### 路径参数

| 参数           | 类型            | 描述                               |
| ------------ | ------------- | -------------------------------- |
| `project_id` | string (UUID) | 项目 ID                            |
| `action_id`  | string (UUID) | 操作 ID（必须是 `forum_engagement` 操作） |

<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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/enrich-forum`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### 响应

```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/..."
  }
}
```

### 错误响应

| 状态    | 原因                         |
| ----- | -------------------------- |
| `400` | 操作不是 `forum_engagement` 类型 |
| `404` | 未找到操作                      |

***

## 执行操作 \[#execute-action]

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

为 `execution.type` 为 `publishable_content` 的 `new_content` 操作启动执行工作流。这会触发文章生成，并带有人工审核检查点（大纲、草稿、终稿）。进度通过 [Webhook](/api-reference/webhooks) 推送。

<Warning>
  仅适用于 `execution.type: "publishable_content"` 的操作。您必须为 `action.checkpoint` 事件注册 webhook 才能接收审核提示。
</Warning>

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |
| `action_id`  | string (UUID) | 操作 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（服务端）">
    ```javascript theme={null}
    const resp = await fetch(`${BASE}/projects/${projectId}/actions/${actionId}/execute`, {
      method: "POST",
      headers,
    });
    ```
  </Tab>
</Tabs>

### 响应（202 Accepted）

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

### 错误响应

| 状态    | 原因                                                             |
| ----- | -------------------------------------------------------------- |
| `400` | 操作不是 `publishable_content` 类型，或不处于 `accepted`/`in_progress` 状态 |
| `404` | 未找到操作                                                          |

***

## 响应检查点

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

响应一个进行中的执行工作流中的审核检查点。在收到 `action.checkpoint` Webhook 事件后调用。

### 路径参数

| 参数           | 类型            | 描述    |
| ------------ | ------------- | ----- |
| `project_id` | string (UUID) | 项目 ID |
| `action_id`  | string (UUID) | 操作 ID |

### 请求体

| 字段               | 类型            | 必填  | 描述                                         |
| ---------------- | ------------- | --- | ------------------------------------------ |
| `workflow_id`    | string (UUID) | Yes | 检查点事件中的工作流 ID                              |
| `decision`       | string        | Yes | `approve`、`edit`、`regenerate` 或 `reject`   |
| `edited_content` | string        | No  | 修改后的内容（当 `decision` 为 `edit` 时必填）          |
| `feedback`       | string        | No  | 用于重新生成的指令（当 `decision` 为 `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（服务端）">
    ```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>

### 响应

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

### 错误响应

| 状态    | 原因                                             |
| ----- | ---------------------------------------------- |
| `400` | 决策无效、缺少 `workflow_id`，或需要但未提供 `edited_content` |
| `404` | 未找到操作或工作流                                      |
| `409` | 工作流当前未在检查点等待                                   |

***

## 获取操作状态

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

返回面向智能体的生命周期快照，不会更改操作。`next_actions` 数组包含下一步有效状态转换或检查点决策的完整 HTTP 请求说明。

```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_..."
```

### 响应

```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" }
        }
      }
    ]
  }
}
```

重复轮询是安全的。服务请求不能使用属于其他项目的操作 ID 或任务 ID。

***

## 列出操作产物

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

列出当前已可获取的产物名称。

| 操作类型         | 可能的产物名称                        |
| ------------ | ------------------------------ |
| 论坛互动         | `thread`、`comment`             |
| 页面 SEO 或内容更新 | `edits`                        |
| 文章工作流        | `research`、`outline`、`article` |

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

***

## 获取操作产物

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

返回一个命名产物。`article` 产物是发布包，包含文章正文、slug、frontmatter、SEO 元数据、JSON-LD 和发布说明。

```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_..."
```

### 错误响应

| 状态码   | 错误代码               | 原因                 |
| ----- | ------------------ | ------------------ |
| `400` | `INVALID_ARTIFACT` | 此产物名称不适用于该操作类型     |
| `404` | `NOT_FOUND`        | 此项目中不存在该操作         |
| `409` | `NOT_READY`        | 产物有效，但工作流尚未到达所需检查点 |

***

## 保存放弃的编辑

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

将进行中的草稿保存到恢复历史，不会推进或取消工作流。这是可恢复的草稿操作，不是提示词删除。

### 请求体

| 字段               | 类型     | 必填 | 说明          |
| ---------------- | ------ | -- | ----------- |
| `workflow_id`    | string | 是  | 活跃工作流 ID    |
| `edited_content` | string | 是  | 需要保留的非空草稿内容 |
| `checkpoint`     | string | 否  | 草稿所属检查点     |

```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"
  }'
```

响应返回 `discarded_edits`，按时间从旧到新排列。每个工作流最多保留 20 条记录。

***

## 列出放弃的编辑

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

返回当前工作流中可恢复的草稿历史。此端点为只读操作。

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