Moda 公共 REST API 位于 https://api.moda.app/v1,适用于没有人工介入的场景,包括定时任务、CI 流水线、Webhook 驱动的工作进程、服务端集成和自定义仪表盘。若用户正在与 AI 代理(如 Claude Desktop、Cursor)对话,应改用 moda-mcp 技能,它负责 OAuth、会话上下文和对话式流程。REST API 与 MCP 可针对同一个 Moda 账户运行。
【前提条件】 基础 URL:https://api.moda.app/v1。认证方式为 Bearer Token,格式为 Authorization: Bearer moda_live_<后缀>。密钥在 设置 → 开发者 → REST API 中创建,仅显示一次,应存入密钥管理器;共 13 个权限范围。每个请求需固定 Moda-Version: 2026-05-01;省略时会解析为当前默认版本(当前为 2026-04-12,并会在日落日期推进)。示例中的每次写入都使用该版本头,所有请求体 JSON 使用带前缀的 ID(cvs_…、task_…、bk_…、file_…)。
【调用 POST /v1/tasks 前的强制检查】 设计任务耗时 2–10 分钟,提前把输入准备好可减少浪费与重试。每次启动任务前执行以下检查:
- 格式:除 slides 外,任何情况下都需显式设置 format_category(slides / social / carousel / pdf / diagram / ui / other)。省略它会无论意图如何都生成幻灯片;允许值与尺寸参见 canvases-and-exports 和 task-envelope 参考。
- 品牌:调用 GET /v1/brand-kits 并选择 brand_kit_id。省略时自动应用团队默认值;要显式退出请设置 skip_brand_kit: true。
- 参考:若任务需要来源文档或风格参考,先 POST /v1/uploads,再在任务上传递 attachments: [{file_id, role}];若以现有画布为灵感,使用 reference_canvas_ids。
- 幂等:对可安全重试的定时任务,传递由稳定键派生的 idempotency_key(如 "weekly-deck:2026-W17")。相同键的重复调用返回同一任务,不会产生重复。
- 交付策略:提前选定一种——Webhook(callback_url)在终止状态触发一次,适合 cron/后端工作进程,仅支持 API 密钥认证(OAuth 调用方会收到 400);轮询 GET /v1/tasks/{id} 按 retry_after_ms 节奏(约 3 秒),适合短生命周期调用方;Prefer: wait=<s>(最长 30 秒)适合快速操作(品牌套件创建、无提示重混),设计任务几乎总超过 30 秒,wait 会超时并返回非终止信封。
- ID:请求体 JSON 中每个 ID 必须带前缀(cvs_…、task_…、bk_…、file_…、conv_…)。路径参数可容忍裸 UUID;在请求体中发送裸 UUID 会返回 400 invalid_request。
【标准流程】 (1) 创建 API 密钥并选择范围 → 设置 → 开发者 → REST API (2) 确保品牌套件存在 → GET /v1/brand-kits(缺失则创建) (3) 上传参考(如有)→ POST /v1/uploads 或 POST /v1/uploads/from-url (4) 启动设计任务 → POST /v1/tasks,携带 format_category 和 callback_url 或 Prefer: wait (5) 接收终止状态 → Webhook(task.succeeded / failed / canceled)或轮询 GET /v1/tasks/{id} (6) 导出画布 → POST /v1/canvases/{id}/export(同步;返回签名 URL)
【核心概念】 13 个权限范围遵循最小权限原则:tasks:write 可启动设计任务,designs:export 可导出,brand_kits:write 可创建套件,完整列表见认证参考。Moda-Version: 2026-05-01 为规范版本,每个请求显式固定;未固定流量会解析为当前默认版本,并在默认版本推进时改变形态。任务信封:每个任务型操作(设计、导出任务、重混、brand_kit_extract)返回 {id, kind, status, result, error, progress, input, credits, links, retry_after_ms},代码应按 status(queued / running / succeeded / failed / canceled / expired)分支。带前缀 ID:响应 id 字段始终带前缀(cvs_、task_、bk_、file_、conv_、evt_、org_、team_);请求体字段要求带前缀形式,路径参数可容忍裸 UUID。带类型的错误信封:{error: {type, code, message, doc_url, request_id, details?, retry_after_ms?, causes?}},应按 type 而非 HTTP 状态码分支,每次错误记录 request_id;对 upstream_error 和 rate_limited 重试,其余修复。游标分页:列表端点返回 {data: [...], next_cursor},迭代直到 next_cursor === null;游标是不透明且签名的,不要手工构造;排序为 (created_at DESC, id DESC)。POST /v1/tasks 上的 idempotency_key 可跨网络超时和工作进程重启安全重试,相同键返回现有任务。callback_url 仅限 API 密钥认证;OAuth 调用方会收到 400,应改用轮询。Webhook 仅在终止状态触发(task.succeeded / task.failed / task.canceled / export.succeeded / export.failed),签名验证为对 {timestamp}.{body} 做 HMAC-SHA256。
【常见任务】 每周 cron 生成状态幻灯片并把 URL 发到 Slack;将 50 个潜在客户的 CSV 转为 50 份个性化幻灯片;把每个团队画布导出为 PDF 到 S3/Drive;接收、验证并处理 Webhook;上传简报 PDF → 品牌幻灯片 → PPTX;GitHub Action 从规范画布重新生成主题令牌。
【错误与重试速查】 invalid_request 不重试,修复请求;authentication 不重试,检查 API 密钥;permission 不重试,添加缺失范围或访问密钥所属团队的资源;not_found 不重试,检查 ID 和团队访问;conflict 不重试,解决状态冲突(通常是名称冲突);idempotency_conflict 不重试,同一幂等键用了不同请求体,修正键或请求体;rate_limited 重试,遵守 Retry-After(秒);upstream_error 重试,上游瞬时失败,退避后重试;internal_error 重试,服务器错误,退避重试并在报告时附 request_id;unprocessable 不重试,输入格式正确但验证失败。
资料中给出了 TypeScript(Node 20+,fetch)和 Python(3.11+,httpx)的最小可用示例,演示启动任务、轮询和导出 PPTX 的完整代码。进一步阅读:docs.moda.app/api(概览)、authentication(密钥与范围)、versioning(Moda-Version 头与迁移映射)、webhooks(负载与签名)、tasks/startTask(完整字段参考)、llms.txt / llms-full.txt(供 LLM 使用的纯文本)。