REST API
cpcp 的 HTTP 接口和网页共用同一条链路:匿名可用、有限流、包裹 1 小时后失效。做 Agent 集成优先用 MCP;需要完全控制请求时用 REST。
先看边界
- 文字最多 64KB;单个文件最多 100MB;每个包裹最多 20 个文件、合计 200MB。
- 包裹 1 小时后过期,最多成功取件 10 次;不需要账号。MCP token 在 /zh/keys 自助生成。
- 接口按 IP 限流;脚本要处理 429 并做退避,不要并发重试。
- 除上传外,请求和响应都是 JSON;错误统一为 { error, message? }。
端点
| 方法 | 路径 | 作用 | 成功响应 |
|---|---|---|---|
| GET | /api/ping | 健康检查 | { ok: true } |
| POST | /api/parcel/text | 寄一个文字包裹 | { code, url, expiresAt } |
| POST | /api/parcel/file/init | 声明一个待上传文件 | { fileId } |
| PUT | /api/parcel/file/:fileId | 上传原始字节 | { ok: true } |
| POST | /api/parcel/seal | 把文件封成一个包裹 | { code, url, expiresAt } |
| GET | /api/parcel/:code | 取件,并消耗一次取件次数 | { kind, text?, files?, expiresAt, remainingClaims } |
| GET | /d/:fileId/:token | 下载单个文件 | 文件流(attachment) |
寄一个文字包裹
请求体:{"content":"hello"},也可以带 ttl(秒,默认 3600)。
curl -s https://<this-site>/api/parcel/text -H 'content-type: application/json' -d '{"content":"hello"}'
返回:{"code":"123456","url":"https://<this-site>/p/123456","expiresAt":1760000000000}。把 code 或 url 交给收件人。
寄一个文件
上传的字节数必须和 init 声明的 size 完全一致,否则返回 400 bad_request;上传成功后重复 PUT 返回 404 no_init,不会覆盖已上传内容。
取件返回 kind 为 file 时,files 数组里每一项包含 name、size 和 downloadUrl。downloadUrl 是带签名的相对路径,只能配合本站域名使用,并随包裹一起过期。
- 声明文件 POST /api/parcel/file/init,请求体 {name, size, mime},拿到 fileId。size 必须等于实际字节数。
- 上传字节 PUT /api/parcel/file/<fileId>,body 是原始字节流。curl -X PUT --data-binary @note.txt -H 'content-type: application/octet-stream'。
- 封箱 POST /api/parcel/seal,请求体 {fileIds:[...]},拿到 6 位取件码。多文件时一次传入全部 fileId。
错误码
| HTTP | error | 什么时候出现 |
|---|---|---|
| 400 | bad_request | JSON 不合法、字段缺失,或上传字节数与声明不符 |
| 400 | too_large | 文字超过 64KB、单文件超过 100MB,或包裹超过 20 件 / 200MB |
| 404 | not_found | 取件码不存在或已用完(与输错码同一句话) |
| 404 | no_init | PUT 的文件不存在、已上传,或不属于待封箱状态 |
| 404 | unknown_file | 封箱时 fileId 不存在,或对应的存储对象不存在 |
| 409 | already_sealed | 文件已经属于另一个包裹 |
| 410 | expired | 取件码存在但已过期(只在 10 分钟宽限窗口内) |
| 429 | rate_limited | 超过按 IP 的限流;等待后重试 |
| 429 | turnstile_required | 同一 IP 多次取件失败;带上 Turnstile token 重试 |
| 503 | busy | 全站配额或取件码池暂时耗尽;稍后重试 |