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

# 发布 API

发布 API 用于把项目当前的生成结果发布为可访问的线上应用，并查询当前线上版本和历史发布记录。

基础地址：`https://meoo.com/open/v1`

## 支持范围

当前 OpenAPI 发布能力支持 `type=web` 项目的默认 Web 发布。采用 Mise 协议的源码项目可通过 `mise.toml` 选择静态站点（`mode=static`）或 HTTP 服务（`mode=server`）。无需 AI 时的项目要求和最小示例见[项目导入与发布](https://app.mintlify.com/alibaba-b47c397f/alibaba-b47c397f/~/2c3751d3-8fbe-4d53-a71b-f992e96c7044)。创建接口虽然也接受 `app` 和 `miniprogram`，但这只表示可以创建和继续操作对应类型的项目，不表示 OpenAPI 已提供其原生发布渠道。

* `app`：本接口不会生成或返回 APK、IPA 等安装包。
* `miniprogram`：本接口不会提交到微信、抖音等小程序平台。
* 请求体不能选择发布渠道；发布项目时可省略请求体、传 \{}，或通过可选 expires\_at 设置发布访问过期时间（Unix 毫秒时间戳）。省略 expires\_at 或传 null 表示永久有效。

在专用发布接口或渠道参数开放前，不要对 `app`、`miniprogram` 项目调用本接口。查询当前版本和发布记录的公开契约也以默认 Web 发布记录为准。

## 发布安全审核

平台会在发布流程中进行内容安全审核。接入方无需单独发起审核，按接口返回结果处理即可。

| 返回结果                                           | 处理方式                                     |
| :--------------------------------------------- | :--------------------------------------- |
| 静态直传 `403 forbidden`                           | 根据 `detail` 修改内容，重新 prepare、上传并 complete |
| 静态直传 `400 artifact_invalid`                    | 根据 `detail` 调整文件格式或大小，重新上传               |
| 静态直传 `503`                                     | 稍后用原 `release_token` 重试 complete，无需重新上传  |
| 普通发布 `release.failed`，`code=content_violation` | 根据 `message` 修改项目内容，再用新的发布 Key 发起发布      |

静态直传审核失败不会替换当前线上版本。排查问题时请提供错误码、错误说明和 `trace_id`。

## 直接上传静态产物

已经在接入方完成构建时，使用两个 API 和一次 PUT 上传，跳过 Meoo 沙箱和构建过程：

1. `POST /projects/{project_id}/releases/prepare`，提交 `runtime=static` 和静态 zip 元数据，**入口文件需要为 index.html**， 获取临时 PUT 地址与 `release_token`；
2. 按响应中的 method、URL、headers 将 zip 直接 PUT 到对象存储；
3. `POST /projects/{project_id}/releases/complete`，只提交 `release_token`，等待自动解压并审核，通过后创建并激活正式 Release。

所需权限：`release.write`

`artifact.content_length` 必传，MD5 checksum 可选。当前仅支持 `artifact.type=static_site`、`content_type=application/zip`，zip 根目录必须包含 `index.html`。`complete` 可使用相同 Token 重试，不接受客户端指定版本号、内部项目 ID 或 OSS 路径。

上传必须携带响应 `upload.headers` 中的全部 Header，包括签名绑定的 `x-oss-forbid-overwrite: true`。首次 PUT 成功后同一对象不能再次上传；省略或修改该 Header 会导致签名校验失败。若 PUT 结果不确定，应调用 complete 确认；修改产物必须重新 prepare，获取新对象地址。升级前未带禁止覆盖约束的票据在 complete 返回 `409 release_state_expired`，需要重新 prepare/upload；已经成功的旧发布仍可重放。

`complete` 返回普通 JSON，不是 SSE；接口内部等待入口文件就绪并执行审核，接入方无需另调审核查询接口。请求超时或返回可重试错误时，用原 `release_token` 重试。普通源码发布仍通过 SSE 等待 `release.completed`。

### 静态发布的访问有效期

`POST /projects/{project_id}/releases/prepare` 可在请求体顶层传 `expires_at`：整数或 null，Unix 毫秒时间戳，合法整数范围为 1～253402271999999。省略或传 null 表示永久有效。请设置未来时间，并为上传、解压和审核预留时间；到期后发布访问地址返回 404。

prepare 请求示例（content\_length 请替换为实际 ZIP 字节数；expires\_at 为示例时间，请替换为实际未来时间）：

```text theme={null}
{
  "runtime": "static",
  "expires_at": 1893456000000,
  "artifact": {
    "type": "static_site",
    "filename": "dist.zip",
    "content_type": "application/zip",
    "content_length": 1024
  }
}
```

prepare 响应中的 `upload.expires_at` 是上传链接的到期时间，与网站的访问到期时间不同；设置网站有效期不会延长上传链接或 release\_token 的有效期。

`POST /projects/{project_id}/releases/complete` 仍只接受 `release_token`，不能在 complete 中新增或修改 expires\_at。服务端沿用 prepare 中的值；成功响应返回 `expires_at`（Unix 毫秒时间戳或 null），重试不会延长有效期。

complete 成功响应示例：

```text theme={null}
{
  "release_id": "123456789012345678",
  "version": 7,
  "artifact_id": "example-artifact",
  "runtime": "static",
  "artifact_type": "static_site",
  "status": "active",
  "access_url": "https://demo.meoo.com",
  "published_at": 1786410060000,
  "expires_at": 1893456000000
}
```

完整请求、响应和两种团队身份模式见[仅部署接入：上传静态产物](https://app.mintlify.com/alibaba-b47c397f/alibaba-b47c397f/~/e0c02cae-8c7f-4fda-b17b-ca6303fe4903)。

### 静态产物的文件要求

| 内容   | 支持范围                                                                                       |
| :--- | :----------------------------------------------------------------------------------------- |
| 静态产物 | 上传可由平台自动解压的 ZIP，根目录有 `index.html`；解压后最多 10000 个文件，总量最多 512 MiB                             |
| 文本   | UTF-8 的 HTML、HTM、JS、MJS、CJS、CSS、JSON、MAP、SVG、TXT、XML、MD、WEBMANIFEST；单文件最多 4 MiB，合计最多 8 MiB |
| 图片   | PNG、JPG、JPEG、WEBP、GIF、BMP；最多 100 张，单张最多 10 MiB，合计最多 50 MiB                                 |
| 辅助资源 | 允许 WOFF、WOFF2、TTF、OTF、EOT 字体和 ICO 图标随包发布                                                   |
| 其他类型 | 暂不支持，包括预压缩的 `.gz`、`.br`、视频和 WASM；超出范围返回 `artifact_invalid`                                 |

## 发布项目

```text theme={null}
POST /projects/{project_id}/releases
```

所需权限：`release.write`

发布过程通过 Server-Sent Events（SSE）持续返回进度。客户端断开不会取消后台发布。

### 请求头

| 请求头                              | 必填 | 说明                                      |
| :------------------------------- | :- | :-------------------------------------- |
| `Authorization`                  | 是  | OAuth Access Token 或 API Key            |
| `Accept: text/event-stream`      | 建议 | 表明客户端接收 SSE                             |
| `Content-Type: application/json` | 否  | 传递 JSON 请求体时使用（包括 expires\_at 或空对象 \{}） |
| `Idempotency-Key`                | 是  | 1～128 个可见 ASCII 字符；用于安全重试               |

同一凭证、用户、项目和 `Idempotency-Key` 在 24 小时内只会启动一次发布。网络中断后使用同一个 Key 重连，会重新返回已保存的发布事件。

### 请求体

请求体可以省略、传空对象 `{}`，或仅包含可选字段 `expires_at`，不接受其他字段。

| 字段          | 类型              | 必填 | 说明                                                          |
| :---------- | :-------------- | :- | :---------------------------------------------------------- |
| expires\_at | integer \| null | 否  | 发布访问过期时间，Unix 毫秒时间戳；整数范围 1～253402271999999。省略或 null 表示永久有效。 |

请设置未来时间并为构建、审核和部署预留时间；到期后发布访问地址返回 404。下面示例中的时间戳需替换为实际未来时间；永久发布使用 \{} 或 \{"expires\_at":null}。

重试同一次发布时，保留原 Idempotency-Key 和相同 expires\_at，不要每次重试重新计算到期时间。同一 Key 修改 expires\_at 会产生幂等冲突；需要使用不同有效期重新发布时，应使用新的 Key。省略 expires\_at 与传 null 都表示永久有效。

### 请求示例

```text theme={null}
curl --no-buffer \
  --request POST \
  --url "https://meoo.com/open/v1/projects/event-signup-demo/releases" \
  --header "Authorization: Bearer ${ACCESS_TOKEN}" \
  --header "Accept: text/event-stream" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: release_20260813_001" \
  --data '{"expires_at":1893456000000}'
```

### 事件列表

| 事件                  | 说明     | 关键字段                                                                    |
| :------------------ | :----- | :---------------------------------------------------------------------- |
| `release.started`   | 发布已开始  | `operation&amp;amp;#95;id`、`started&amp;amp;#95;at`                     |
| `release.progress`  | 发布进度更新 | `operation&amp;amp;#95;id`、`progress`、`message`、`timestamp`             |
| `release.completed` | 发布成功   | operation\_id、release\_id、version、access\_url、published\_at、expires\_at |
| `release.failed`    | 发布失败   | `operation&amp;amp;#95;id`、`code`、`message`、`failed&amp;amp;#95;at`     |

事件中的时间字段均为 Unix 毫秒时间戳。每个事件还包含递增的 SSE `id`。 `release.failed.message` 会返回可安全展示给用户的失败原因，例如构建产物异常、代码构建失败或额度不足。可由代码修复的失败会在同一字段中附带经过脱敏的构建错误，供 AI 定位文件、行列和编译问题；字段最长 4000 字符，不会透传凭证、内部地址或原始上游响应。

### 事件流示例

```text theme={null}
id: 1
event: release.started
data: {"operation_id":"rel_01JEXAMPLE","started_at":1786410000000}

id: 2
event: release.progress
data: {"operation_id":"rel_01JEXAMPLE","progress":60,"message":"正在部署应用","timestamp":1786410030000}

id: 3
event: release.completed
data: {"operation_id":"rel_01JEXAMPLE","release_id":"123456789012345678","version":7,"access_url":"https://*.mobao.app","published_at":1786410060000,"expires_at":1893456000000}
```

收到 `release.completed` 或 `release.failed` 后，本次发布结束。SSE 注释帧是保持连接使用的心跳，可以忽略。

`release.completed.expires_at` 为本次发布的访问过期时间，类型为 integer | null；整数使用 Unix 毫秒时间戳，null 表示永久有效。接入方应连同 release\_id、access\_url 一起保存该字段；事件重放不会延长发布有效期。

### 发布失败示例

```text theme={null}
event: release.failed
data: {"operation_id":"rel_01JEXAMPLE","code":"release_failed","message":"应用代码构建失败，请检查代码后重试\n构建失败: src/App.tsx(12,3): error TS2322: Type 'string' is not assignable to type 'number'","failed_at":1786410060000}
```

常见发布错误码：

| 错误码                                         | 说明                                 |
| :------------------------------------------ | :--------------------------------- |
| `duplicate&amp;amp;#95;release`             | 项目已有发布任务正在进行                       |
| `project&amp;amp;#95;not&amp;amp;#95;found` | 项目不存在或当前用户不能访问                     |
| `content&amp;amp;#95;violation`             | 项目内容未通过安全检查                        |
| `quota&amp;amp;#95;exceeded`                | 当前账号额度不足                           |
| `release&amp;amp;#95;failed`                | 发布失败                               |
| `release&amp;amp;#95;interrupted`           | 发布任务中断，需要使用新的 `Idempotency-Key` 重试 |

如果连接在发布过程中断，先用原 `Idempotency-Key` 重连。只有服务端明确返回 `release_interrupted` 或恢复状态已过期时，才生成新的 Key 发起新发布。

## 取消当前发布

```text theme={null}
POST /projects/{project_id}/releases/unpublish
```

所需权限：`release.write`。调用身份必须拥有项目 Owner 或 Admin 权限。

该接口复用应用取消发布流程：取消当前 active Release，并同步移除关联橱窗展示和模板公开指针；历史发布记录仍然保留。请求体可以省略或传空对象 \{}，不接受 expires\_at。此接口用于主动取消当前发布，不用于设置、延长或清除发布有效期。

```text theme={null}
curl --request POST \
  --url "https://meoo.com/open/v1/projects/event-signup-demo/releases/unpublish" \
  --header "Authorization: Bearer ${ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data '{}'
```

成功返回：

```text theme={null}
{
  "status": "unpublished",
  "previous_version": "7",
  "showcase_removed": true,
  "template_unpublished": false,
  "unpublished_at": 1786410060000
}
```

项目当前未发布时返回 `404 release_not_found`；项目仍在发布过程中时返回 `409 release_conflict`。

## 查询当前线上版本

```text theme={null}
GET /projects/{project_id}/releases/current
```

所需权限：`release.read`

返回项目当前对外提供服务的版本。当前此接口不返回 expires\_at；接入方需要展示或管理发布有效期时，请保存发起发布时的 expires\_at，以及 complete 成功响应或 release.completed 事件返回的值。

### 请求示例

```text theme={null}
curl --request GET \
  --url "https://meoo.com/open/v1/projects/event-signup-demo/releases/current" \
  --header "Authorization: Bearer ${ACCESS_TOKEN}"
```

### 响应字段

| 字段                         | 类型             | 说明                            |
| :------------------------- | :------------- | :---------------------------- |
| `release&amp;amp;#95;id`   | string         | 发布记录标识，以字符串返回                 |
| `version`                  | integer        | 版本号                           |
| `status`                   | string         | 当前固定为 `active`                |
| `access&amp;amp;#95;url`   | string \| null | 完整 HTTPS 应用访问地址；暂未生成时为 `null` |
| `published&amp;amp;#95;at` | integer        | 发布时间，Unix 毫秒时间戳               |

### 响应示例

```text theme={null}
{
  "release_id": "123456789012345678",
  "version": 7,
  "status": "active",
  "access_url": "https://demo.meoo.com",
  "published_at": 1786410060000
}
```

项目尚未发布时返回 `404`，错误码为 `release_not_found`。

## 查询发布记录

```text theme={null}
GET /projects/{project_id}/releases
```

所需权限：`release.read`

按版本从新到旧分页返回项目的发布记录。

### Query 参数

**参数说明**

* `page_size`（integer，可选）：每页数量，默认 20，最大 100
* `page_token`（string，可选）：上一页响应中的分页令牌

### 请求示例

```text theme={null}
curl --request GET \
  --url "https://meoo.com/open/v1/projects/event-signup-demo/releases?page_size=20" \
  --header "Authorization: Bearer ${ACCESS_TOKEN}"
```

### 响应字段

| 字段 | 类型 | 说明 |
| :- | :- | :- |

\| `items[ ].release_id` | string | 发布记录标识 |

\| `items[ ].version` | integer | 版本号 |

\| `items[ ].status` | string | 发布状态 |

\| `items[ ].created_at` | integer | 发布记录创建时间 |

\| `items[ ].finished_at` | integer | 发布结束或最近更新时间 |

\| `items[ ].current` | boolean | 是否为当前线上版本 |

\| `next_page_token` | string | 下一页令牌；没有下一页时不返回 |

列表只返回已经持久化的发布记录。当前默认发布流程在成功后写入记录，发布中的实时进度和失败结果以同一 `Idempotency-Key` 对应的 SSE 事件流为准，不应轮询本接口代替 SSE。状态枚举为 `processing`、`succeeded`、`failed`、`canceled`、`active` 或 `unknown`，用于兼容其他发布渠道和后续扩展；客户端应能展示未知状态，而不是将其视为接口错误。

当前历史列表不返回 `items[].expires_at`，也不提供单独修改发布有效期的接口。接入方应按 release\_id 保存发布成功响应或 release.completed 事件中的 expires\_at；需要不同有效期时重新发起发布。

### 响应示例

```text theme={null}
{
  "items": [
    {
      "release_id": "123456789012345678",
      "version": 7,
      "status": "active",
      "created_at": 1786410000000,
      "finished_at": 1786410060000,
      "current": true
    },
    {
      "release_id": "123456789012345600",
      "version": 6,
      "status": "succeeded",
      "created_at": 1786320000000,
      "finished_at": 1786320060000,
      "current": false
    }
  ],
  "next_page_token": "eyJ2IjoxLCJjdXJzb3IiOiJleGFtcGxlIn0"
}
```

## 常见错误

| HTTP 状态       | 说明                                                                               |
| :------------ | :------------------------------------------------------------------------------- |
| `400`         | Idempotency-Key、请求体或分页参数不符合要求；expires\_at 类型错误、非整数、为 0 或超出范围时返回 invalid\_request |
| `403`         | 缺少发布权限，或当前账号/项目不能发布                                                              |
| `404`         | 项目或当前线上版本不存在，或当前用户不能访问                                                           |
| `409`         | 项目正在发布，或可恢复的发布状态已失效                                                              |
| `429`         | 发布或查询频率超过限制                                                                      |
| `500` / `503` | 发布服务暂时不可用                                                                        |

发布接口会使用项目当前的生成结果。调用前请确保 AI 生成任务已经完成，并由你的产品向用户明确展示即将发布的项目。

## 从已有源码开始

使用[源码导入 API](https://app.mintlify.com/alibaba-b47c397f/alibaba-b47c397f/~/91f543e7-3294-43b9-9690-d60c1e5c1aa5)创建新 Web 项目，等待 `import.completed`；如果开启 AI，再通过原有 Agent 接口等待 Run 完成，最后调用普通发布接口。导入不会自动发布，也不支持覆盖导入。导入完成前请勿编辑、启动 Agent、发布或删除该项目。发布的是当前源码，接入方无需传 commitId 或手动推送 NAS。
