跳到正文

REST API ​

控制台建立在 https://zenavo.app/api 上的 JSON REST API 之上。控制台能做的事,都可以用它来做。

认证 ​

以 Bearer 令牌的形式发送 API 密钥:

sh
curl -H "Authorization: Bearer $ZENAVO_API_KEY" https://zenavo.app/api/auth/me

密钥的权限和项目限制决定它可以调用哪些接口;其他接口返回 403。账单、购买、团队成员和 /api/account/* 只能通过浏览器会话使用。

来自浏览器会话的请求,除 GET 以外都还需要带上请求头 X-Zenavo-Request: 1;使用 Bearer 令牌的请求不需要。

请求只需要有效的会话或拥有相应角色的 API 密钥;没有任何操作要求二次确认。尚未验证邮箱的账号对自己账号以外的修改会收到 403 和 {"email_unverified": true}。

约定 ​

  • 请求体是 JSON。时间是 Unix 秒。
  • ID 带有前缀:team_、srv_、proj_、job_、bak_、tok_。
  • 错误返回状态码和 {"detail": …}。校验错误(422)会列出每个字段。
  • 耗时较长的操作(部署、重启、备份)返回一个任务:{"id": "job_…"}。轮询 GET /api/jobs/{id} 获取 status(queued、running、succeeded、failed)、log 和每个服务的 progress。

接口 ​

账号 ​

方法路径
GET/api/auth/me当前登录的用户、所在的团队和 email_verified
PATCH/api/account名称和头像
GET POST/api/account/tokens列出或创建 API 密钥(仅限浏览器会话)。创建时传入 {name, days, scope, project_ids}:scope 为 read、deploy 或 full(默认);project_ids 把密钥限定在这些项目(省略或 null 表示全部)
DELETE/api/account/tokens/{id}删除 API 密钥
GET/api/account/sessions已登录的会话
POST/api/auth/2fa登录的第二步:在 /api/auth/login 返回 {two_factor: true} 后提交 {code}
POST/api/account/verify确认身份:开启两步验证时提交 {code},否则提交 {password}。目前没有操作需要它
POST/api/auth/verify-email打开邮箱验证链接:{token}(只能使用一次,24 小时内有效)
POST/api/account/email/verify发送新的验证链接;地址已验证时返回 {verified: true}
GET/api/account/2fa两步验证状态:enabled(应用或通行密钥)、totp、剩余恢复码数量、通行密钥数量
POST/api/account/2fa/setup /enable /disable /recovery-codes管理两步验证(仅限浏览器会话)
POST/api/auth/2fa/passkey/options 然后 /api/auth/2fa/passkey用通行密钥完成登录的第二步:WebAuthn 请求选项(没有通行密钥时为 {options: null})以及账号是否有身份验证器应用(totp),然后提交 {credential}
GET/api/account/passkeys你的通行密钥:名称、AAGUID、是否同步、创建时间、最近使用时间
POST/api/account/passkeys/options 然后 /api/account/passkeys注册通行密钥:先获取创建选项,再提交 {name, credential}(账号的第一个第二重验证方式还会返回 recovery_codes)
DELETE/api/account/passkeys/{id}移除通行密钥(移除最后一个第二重验证方式会关闭两步验证)
GET/api/account/audit?before=&limit=你自己的安全活动
POST/api/auth/device/code开始 CLI 登录(设备流程):{client_name, scope, client} → {device_code, user_code, verification_uri, expires_in, interval}。scope 默认为 full;client 为 cli(默认)或 mcp,密钥分别命名为“CLI on …”或“MCP on …”
POST/api/auth/device/token用 {device_code} 轮询:等待中返回 202,轮询快于 interval 返回 429,批准后返回 200 {token, scope, project_ids}(批准人可能缩小了范围)

团队 ​

方法路径
GET POST/api/teams列出或创建团队
PATCH/api/teams/{tid}重命名
GET/api/teams/{tid}/members成员
PATCH DELETE/api/teams/{tid}/members/{uid}修改角色、移除成员
GET POST/api/teams/{tid}/invites邀请
GET/api/teams/{tid}/audit?before=&limit=审计日志(管理员)
GET POST/api/teams/{tid}/notification-channels通知渠道(管理员)。创建时传入 {kind, name, events, url}(Slack、Discord、Webhook)或 {kind: "telegram", name, events, bot_token, chat_id};Webhook 的 secret 只返回一次
PATCH DELETE/api/teams/{tid}/notification-channels/{cid}修改 name、events、enabled 或目标地址;移除
POST/api/teams/{tid}/notification-channels/{cid}/test立即发送一条测试消息
POST/api/teams/{tid}/notification-channels/{cid}/secretWebhook 的新签名密钥(只返回一次)
GET POST/api/teams/{tid}/log-drains日志转发(管理员;创建需要 Pro 及以上套餐)。创建时传入 {kind: "http", name, url}、{kind: "datadog", name, site, api_key} 或 {kind: "loki", name, url, username, password, tenant_id},再加上 projects(为空表示全部);HTTP 转发目标的 secret 只返回一次
PATCH DELETE/api/teams/{tid}/log-drains/{did}修改 name、projects、enabled 或目标地址;移除
POST/api/teams/{tid}/log-drains/{did}/test立即发送一行测试日志
POST/api/teams/{tid}/log-drains/{did}/secretHTTP 转发目标的新签名密钥(只返回一次)

用量与账单 ​

方法路径
GET/api/teams/{tid}/usage?period=YYYY-MM套餐额度、服务器、成员,以及按项目、服务和日期统计的构建分钟数
GET/api/teams/{tid}/usage/builds.csv?period=某个月每一次计量的构建,CSV 格式
GET/api/teams/{tid}/transfer本周期的镜像传输:bytes、included_bytes、overage_cents、limit_cents、blocked、percent,以及周期的开始和结束时间
GET/api/teams/{tid}/billing套餐、订阅状态、席位和套餐目录(管理员)
GET/api/teams/{tid}/billing/invoices最近的发票,附 Stripe 页面和 PDF 链接(管理员)
GET/api/teams/{tid}/server-billing购买的服务器及其已付费月份和自动续费状态,以及最近的服务器扣款(管理员)
POST/api/teams/{tid}/billing/checkout开始订阅:{plan} → Stripe Checkout 的 {url}(所有者)
POST/api/teams/{tid}/billing/change把订阅切换到其他套餐:{plan}(所有者)
POST/api/teams/{tid}/billing/cancel /resume在周期结束时取消,或撤销取消(所有者)
PUT/api/teams/{tid}/billing/spend-limit设置消费上限:{cents},0 到 1,000,000(所有者)
POST/api/teams/{tid}/billing/portalStripe 客户门户的 {url},用于管理卡片、账单信息和发票(所有者)

服务器 ​

方法路径
GET/api/servers?team_id=列出服务器
POST/api/servers?team_id=添加服务器:{name, host, port, user, password | private_key}
GET PATCH/api/servers/{sid}读取、重命名
POST/api/servers/{sid}/bootstrap重新运行初始化:{password | private_key};初始化失败后一天内可以传空请求体,沿用保留的凭据
PATCH/api/servers/{sid}/billing购买的服务器的自动续费:{auto_renew}(管理员)。GET /api/servers/{sid} 在 bought 下显示它,以及 paid_until
POST/api/servers/{sid}/renew立即支付购买的服务器下个月的费用(管理员)
GET/api/servers/{sid}/usage?hours=CPU、内存和磁盘的历史数据
GET/api/servers/{sid}/system平台组件
GET/api/servers/{sid}/ports端口检查
GET/api/servers/{sid}/jobs初始化和其他任务
POST/api/servers/{sid}/delete移除:{confirmation: "<server name>"}
POST/api/servers/{sid}/reinstall卸载 K3s 并从头初始化服务器:{confirmation: "<server name>", password | private_key}(管理员;服务器上不能有项目)。返回服务器,初始化已进入队列
POST/api/servers/{sid}/reinstall-os重装购买的服务器的操作系统并从头初始化,不需要 SSH 凭据;新的登录密码会邮件发给调用者:{confirmation: "<server name>"}(管理员;服务器上不能有项目,且其 bought.reinstall_os 为 true)。返回服务器,重装已排队
GET/api/servers/{sid}/ssh-logins?hours=&failed=SSH 登录记录(成员)
POST/api/servers/{sid}/agent把在 agent 之前添加的服务器迁移到 agent(管理员)
POST/api/servers/{sid}/agent/update更新 agent(管理员;返回一个任务)
GET/api/servers/{sid}/firewall服务器的防火墙(成员)。购买的服务器:Zenavo 的固定规则(Web、HTTPS、ping、初始化用的 SSH)和团队的规则,在服务商处生效;你接入的服务器:需要在那里开放的端口
POST/api/servers/{sid}/firewall/rules为购买的服务器添加放行规则:{protocol, ports, sources, note},protocol 为 tcp、udp 或 icmp,ports 例如 8080 或 30000-30100,sources 是地址或 CIDR 网段列表(管理员;最多 30 条)
PUT DELETE/api/servers/{sid}/firewall/rules/{rid}修改规则(请求体相同)或删除规则(管理员)
POST/api/servers/{sid}/firewall/apply服务商处应用失败后,重新应用规则(管理员)

项目 ​

方法路径
GET/api/projects?team_id=列出项目
POST/api/projects创建:{team_id, server_id, manifest}
GET/api/projects/{pid}概要、服务和状态
GET/api/projects/{pid}/manifest完整配置,包括变量
PUT/api/projects/{pid}保存配置:{manifest, server_id, revision}
POST/api/projects/{pid}/deploy部署所有服务(返回一个任务)
POST/api/projects/{pid}/rollback{target_job}
POST/api/projects/{pid}/services/{service}/rollback{target_job}:把一个服务恢复到那次部署;其他服务保持当前部署(返回一个任务)
POST/api/projects/{pid}/restart /stop重启或停止所有服务
GET/api/projects/{pid}/runtime每个服务的实时状态
POST/api/projects/{pid}/clone /transfer复制:{name, team_id, server_id};或者把从未部署过的项目转移到其他团队:{team_id, server_id}(需要是两个团队的管理员)
GET/api/projects/{pid}/move最近一次迁移到其他服务器
GET/api/projects/{pid}/move/preflight?server_id=检查迁移,不做任何改动(管理员)
POST/api/projects/{pid}/move把项目连同数据迁移到团队的另一台服务器:{server_id, confirmation: "<project name>"}(管理员;返回一个任务)
POST/api/projects/{pid}/move/finish /move/rollback删除旧副本,或回到旧服务器(管理员;返回一个任务)
POST/api/projects/{pid}/delete{confirmation: "<project name>"}
PUT/api/projects/{pid}/checklist迁移检查清单:{source_backup, data_restored, application_verified, dns_switched, rollback_ready},每项为 true 或 false(成员)

服务 ​

{service} 是服务 ID;服务当前的名称也可以使用。在项目的配置中,每个服务都有一个 id 和一个可选的 hostname;新服务两者都不填时,Zenavo 会给它一个随机的 svc-… ID,并根据名称生成主机名。

方法路径
POST/api/projects/{pid}/services/{service}/deploy只部署这个服务;其他服务保持当前部署(返回一个任务)
PUT/api/projects/{pid}/services/{service}/source?create=&port=&deploy=&acknowledge_init=上传一个目录的 gzip 压缩 tar 包(最大 500 MB)作为服务的来源并部署(返回 {upload_id, service, created, job});create=1 会添加不存在的服务,deploy=0 只保存不部署
POST/api/projects/{pid}/services/{service}/restart /suspend /resume
POST/api/projects/{pid}/services/{service}/exec在容器中运行命令
GET/api/projects/{pid}/services/{service}/terminalWebSocket:交互式终端(成员)。二进制帧传输输入和输出;文本帧传输 JSON:客户端发送 {"type":"resize","cols","rows"},服务端发送 {"type":"exit","code"} 或 {"type":"error","message"}。浏览器必须发送控制台的 Origin
GET/api/projects/{pid}/services/{service}/files?path=列出容器中的文件夹(成员)
GET/api/projects/{pid}/services/{service}/files/content?path=文件的前 256 KB,以文本形式返回
GET/api/projects/{pid}/services/{service}/files/download?path=下载文件(最大 500 MB)
PUT/api/projects/{pid}/services/{service}/files/upload?dir=&name=上传原始请求体(最大 50 MB,必须提供 Content-Length);&overwrite=1 会替换已有文件
POST/api/projects/{pid}/services/{service}/files/mkdir新建文件夹:{"path"}
POST/api/projects/{pid}/services/{service}/files/rename原地重命名:{"path", "name"}
POST/api/projects/{pid}/services/{service}/files/delete删除文件或文件夹:{"path"}
GET/api/projects/{pid}/services/{service}/usage?hours=CPU 和内存的历史数据
GET/api/projects/{pid}/logs/{service}最近的运行日志
GET/api/projects/{pid}/logs/{service}/stream实时运行日志(Server-Sent Events)
GET/api/projects/{pid}/logs/{service}/history?from=&to=&q=&cursor=&limit=已保存的运行日志,从旧到新:from 和 to 之间包含 q(不区分大小写)的行(RFC 3339 或 Unix 秒;默认最近一小时)。把返回的 next 作为 cursor 传回即可获取更多
GET/api/projects/{pid}/logs/{service}/download?from=&to=&q=把某个时间范围内已保存的运行日志下载为文本文件
POST/api/projects/{pid}/services/{service}/domains生成域名
DELETE/api/projects/{pid}/domains/{domain}移除生成的域名

数据库视图 ​

数据库服务的数据库视图。成员可以读取;写入需要团队管理员。每个请求都在数据库容器内运行,并记录在审计日志中,但不记录 SQL、键、值或文档。 … 即 /api/projects/{pid}/services/{service}。

方法路径
GET…/database/tablesPostgreSQL、MySQL、MariaDB:表和视图,以及估算的行数和列
GET…/database/rows?schema=&table=&offset=&limit=一页表数据
POST…/database/query执行一条 SQL 语句:{sql, allow_writes, max_rows}。除非 allow_writes(管理员),否则只读
POST…/database/keysRedis、Valkey:用 SCAN 列出键:{db, match, cursor, count}
POST…/database/key单个键的值:{db, key, cursor, count};不是 UTF-8 的键用 key_b64
POST…/database/command执行一条命令:{db, command, allow_writes}。除非 allow_writes(管理员),否则只能执行读取命令
GET…/database/collectionsMongoDB:数据库和集合,以及估算的文档数
POST…/database/find查询文档:{db, collection, filter, sort, projection, skip, limit},均为 JSON 字符串;默认每页 50 个
POST…/database/document修改一个文档:{op, db, collection, filter, update, document},op 为 insert、update 或 delete(管理员)

备份 ​

方法路径
GET/api/backups?project_id=列出备份
POST/api/projects/{pid}/backups备份一个服务:{service, engine}
GET/api/backups/{bid}/download下载
POST/api/backups/{bid}/restore恢复:{confirmation},与控制台中输入的内容相同

Git 与 GitHub ​

方法路径
POST/api/git/refs公开仓库的分支和标签:{url}
POST/api/git/plan构建计划预览:{team_id, url, ref, context}
GET/api/github/repos?team_id=团队的 GitHub 安装可以读取的仓库
GET/api/github/branches?team_id=&repo=其中某个仓库的分支

镜像与域名 ​

方法路径
GET/api/images/ports?team_id=&image=公开镜像 EXPOSE 的端口,从镜像仓库读取,不拉取镜像
GET/api/images/mirror?image=Zenavo 面向中国大陆的镜像是否有某个镜像,以及它在镜像站中的地址
GET/api/images/mirror/search?q=镜像站中名称包含 q 的镜像
GET/api/domains/available?name=某个生成的域名是否可用:{available, reason}

模板 ​

方法路径
GET/api/templates模板库(公开,不需要密钥)
GET/api/templates/{code}单个模板及其 manifest(公开)
POST/api/imports/preview检查 Zeabur 模板或 Zenavo 导出文件:{text, team_id, variables};或者模板库中的模板:{template, team_id, variables}
POST/api/imports/{did}/commit创建项目:{server_id}

示例:部署并等待完成 ​

sh
JOB=$(curl -s -X POST -H "Authorization: Bearer $ZENAVO_API_KEY" \
  -H "Content-Type: application/json" -d '{}' \
  https://zenavo.app/api/projects/$PROJECT/deploy | jq -r .id)

until curl -s -H "Authorization: Bearer $ZENAVO_API_KEY" https://zenavo.app/api/jobs/$JOB \
  | jq -e '.status == "succeeded" or .status == "failed"' >/dev/null; do sleep 5; done

与 Zeabur 无关联。