注意:以下内容适用于有一定技术能力的用户,否则请跳过此页面!!!
本文档说明如何直接调用 Metapi 管理后台的 /api/* 接口,用脚本完成站点与账号管理。
这组接口适合以下场景:
- 初始化新实例,批量导入站点和账号
- 用 Shell / Python / CI 脚本维护现有管理数据
- 在外部系统里接入 Metapi 后台能力,而不是手工点页面
Important
本页介绍的是 管理 API,不是下游客户端调用的 /v1/* 代理接口。
- 管理 API 使用
AUTH_TOKEN - 代理接口使用
PROXY_TOKEN
所有受保护的管理接口都需要携带:
Authorization: Bearer <AUTH_TOKEN>其中:
AUTH_TOKEN就是你启动 Metapi 时配置的管理员令牌- 如果你后来在「设置」里修改过管理员令牌,脚本里也要同步改成新值
- 管理端如果启用了
ADMIN_IP_ALLOWLIST,脚本调用方的来源 IP 也必须命中白名单
管理 API 不需要额外先调用“登录接口”;脚本直接带 AUTH_TOKEN 即可。
推荐先准备两个环境变量:
export METAPI_ADMIN_BASE_URL="http://127.0.0.1:4000"
# 或者
# export METAPI_ADMIN_BASE_URL="https://your-domain.com"
export METAPI_AUTH_TOKEN="your-admin-token"之后所有请求都可以复用:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/sites" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}"| 项目 | 说明 |
|---|---|
| 接口前缀 | 管理接口统一在 /api/* |
| 请求体 | 默认使用 application/json |
| 认证方式 | Authorization: Bearer <AUTH_TOKEN> |
| 成功判定 | 除了看 HTTP 状态码,也要看响应体里的 success / error / message |
| 业务失败返回 | 有些接口会返回 200,但响应体里是 success: false |
| 常见错误码 | 400 参数错误、401/403 认证失败、409 资源冲突、429 触发限流 |
Tip
对脚本来说,最稳妥的做法是:
- 先检查 HTTP 状态码
- 再检查返回 JSON 里的
success、error、message - 不要只靠
200判断调用成功
脚本化添加一个新站点并绑定账号,通常按下面顺序:
POST /api/sites/detect自动识别平台- 如命中官方预设,记下返回的
initializationPresetId POST /api/sites创建站点POST /api/accounts/verify-token验证凭证POST /api/accounts保存账号
如果你要自动化的是 Codex / Claude / Gemini CLI / Antigravity 这类 provider 授权,则改看本文后面的 OAuth 接口,不要强行走普通账号导入。
最小流程示例:
# 1. 自动识别站点类型
curl -sS "${METAPI_ADMIN_BASE_URL}/api/sites/detect" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com"
}'
# 2. 创建站点
curl -sS "${METAPI_ADMIN_BASE_URL}/api/sites" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "My New API",
"url": "https://api.example.com",
"platform": "new-api"
}'
# 3. 验证 API Key 或 Session Token
curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts/verify-token" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"siteId": 1,
"accessToken": "sk-or-session-token",
"credentialMode": "apikey"
}'
# 4. 保存账号
curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"siteId": 1,
"accessToken": "sk-or-session-token",
"credentialMode": "apikey"
}'GET /api/sites
返回当前全部站点。响应除了站点自身字段,还会带上聚合出来的 totalBalance 和 subscriptionSummary。
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/sites" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}"示例响应:
[
{
"id": 1,
"name": "My New API",
"url": "https://api.example.com",
"platform": "new-api",
"status": "active",
"useSystemProxy": false,
"totalBalance": 42.5,
"subscriptionSummary": null
}
]POST /api/sites/detect
用于在真正创建站点前,先根据 URL 探测平台类型;如果命中官方预设,还会顺带返回 initializationPresetId。
请求体:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
url |
string |
是 | 待识别的站点地址。通用平台通常传根地址;如果你想命中官方预设,则直接传预设对应的完整地址 |
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/sites/detect" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.example.com"
}'成功响应:
{
"url": "https://api.example.com",
"platform": "new-api"
}命中预设时,响应可能类似:
{
"url": "https://coding.dashscope.aliyuncs.com/v1",
"platform": "openai",
"initializationPresetId": "codingplan-openai"
}失败响应:
{
"error": "Could not detect platform"
}POST /api/sites
请求体字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
string |
是 | 站点名称 |
url |
string |
是 | 站点地址。通用平台通常用根地址;官方预设可直接保留完整官方路径 |
platform |
string |
否 | 平台类型;留空时服务端会再次尝试自动识别 |
initializationPresetId |
string |
否 | 官方预设 ID;用于保留预设语义、初始化建议和后续跳转 |
proxyUrl |
string | null |
否 | 站点专用代理地址,支持 http(s) / socks |
useSystemProxy |
boolean |
否 | 是否使用全局 SYSTEM_PROXY_URL |
customHeaders |
string | null |
否 | 自定义请求头,注意这里传的是 JSON 字符串 |
externalCheckinUrl |
string | null |
否 | 外部签到地址,需为 http(s) |
status |
string |
否 | active 或 disabled |
isPinned |
boolean |
否 | 是否置顶 |
sortOrder |
number |
否 | 排序值,非负整数 |
globalWeight |
number |
否 | 站点全局权重,必须为正数 |
apiEndpoints |
array |
否 | 仅用于 API 请求的数据面地址池;不替代主站点 URL |
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/sites" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Proxy Site",
"url": "https://proxy-site.example.com",
"platform": "new-api",
"proxyUrl": "socks5://127.0.0.1:1080",
"useSystemProxy": true,
"customHeaders": "{\"cf-access-client-id\":\"site-client-id\",\"x-site-scope\":\"internal\"}",
"externalCheckinUrl": "https://checkin.example.com/welfare",
"globalWeight": 1.5
}'成功响应示例:
{
"id": 1,
"name": "Proxy Site",
"url": "https://proxy-site.example.com",
"platform": "new-api",
"proxyUrl": "socks5://127.0.0.1:1080",
"useSystemProxy": true,
"customHeaders": "{\"cf-access-client-id\":\"site-client-id\",\"x-site-scope\":\"internal\"}",
"externalCheckinUrl": "https://checkin.example.com/welfare",
"status": "active",
"globalWeight": 1.5
}常见失败:
409:同一个(platform, url)已存在400:proxyUrl、externalCheckinUrl、customHeaders、globalWeight等字段格式不合法
Tip
customHeaders 不是对象,而是 JSON 字符串;并且 value 必须是字符串。
如果你前一步 detect 已经拿到了 initializationPresetId,推荐在创建时显式带回去:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/sites" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "Aliyun CodingPlan",
"url": "https://coding.dashscope.aliyuncs.com/v1",
"platform": "openai",
"initializationPresetId": "codingplan-openai"
}'这样响应里也会保留该预设信息,便于脚本按预设类型做后续分流。
GET /api/accounts
返回账号快照对象,而不是裸数组。响应里包含:
generatedAt:快照生成时间accounts:当前全部账号,以及关联站点、凭证模式、能力信息、今日花费、运行健康状态等聚合字段sites:前端常用的站点列表快照
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}"示例响应:
{
"generatedAt": "2026-04-09T06:00:00.000Z",
"accounts": [
{
"id": 1,
"siteId": 1,
"username": "alice",
"status": "active",
"credentialMode": "apikey",
"capabilities": {
"canCheckin": false,
"canRefreshBalance": false,
"proxyOnly": true
},
"site": {
"id": 1,
"name": "My New API",
"url": "https://api.example.com",
"platform": "new-api"
}
}
],
"sites": [
{
"id": 1,
"name": "My New API",
"url": "https://api.example.com",
"platform": "new-api"
}
]
}POST /api/accounts/verify-token
建议在真正保存账号前先调用一次。这样脚本可以在入库前拿到更明确的错误信息。
请求体字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
siteId |
number |
是 | 目标站点 ID |
accessToken |
string |
是 | Session Token / Session Cookie / API Key |
platformUserId |
number |
否 | 某些 new-api / anyrouter 站点需要手动传 |
credentialMode |
string |
否 | auto / session / apikey,脚本里推荐显式传 |
curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts/verify-token" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"siteId": 1,
"accessToken": "sk-fast-verify",
"credentialMode": "apikey"
}'成功响应:
{
"success": true,
"tokenType": "apikey",
"modelCount": 2,
"models": ["gpt-5-mini", "gpt-4o-mini"]
}curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts/verify-token" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"siteId": 1,
"accessToken": "session=xxxx",
"credentialMode": "session"
}'成功响应:
{
"success": true,
"tokenType": "session",
"userInfo": {
"username": "alice"
},
"balance": 12.34,
"apiToken": "sk-generated-by-upstream"
}Tip
对 new-api / anyrouter 一类站点,如果返回 needsUserId: true,说明脚本里要补上 platformUserId 再重试。
POST /api/accounts
请求体字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
siteId |
number |
是 | 目标站点 ID |
accessToken |
string |
是 | 输入凭证;即使是 API Key 模式,也先放这里 |
username |
string |
否 | 用户名;Session 模式下通常可由服务端自动识别 |
apiToken |
string |
否 | 可显式指定要保存的 API Key;留空时服务端会自动推断 |
platformUserId |
number |
否 | 平台用户 ID,New API 系站点常用 |
checkinEnabled |
boolean |
否 | Session 模式下是否开启签到 |
credentialMode |
string |
否 | auto / session / apikey |
refreshToken |
string |
否 | sub2api 会话可附带刷新令牌 |
tokenExpiresAt |
number | string |
否 | sub2api 会话过期时间戳 |
skipModelFetch |
boolean |
否 | 为 true 时可跳过即时模型拉取 |
curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"siteId": 1,
"accessToken": "sk-proxy-only",
"credentialMode": "apikey"
}'成功响应示例:
{
"id": 1,
"siteId": 1,
"tokenType": "apikey",
"credentialMode": "apikey",
"capabilities": {
"canCheckin": false,
"canRefreshBalance": false,
"proxyOnly": true
},
"modelCount": 1,
"apiTokenFound": true,
"queued": true,
"jobId": "task_xxx",
"message": "已添加为 API Key 账号,后台正在同步模型和路由信息。"
}curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"siteId": 1,
"accessToken": "session=xxxx",
"credentialMode": "session",
"platformUserId": 1001,
"checkinEnabled": true
}'常见失败:
400+requiresVerification: true:凭证还没有通过验证,建议先调用/api/accounts/verify-token400:siteId不存在、Token 为空、凭证类型与credentialMode不匹配
Tip
对纯脚本导入场景,建议始终显式传 credentialMode,不要依赖 auto 推断。
POST /api/accounts/:id/rebind-session
用于账号 Session 过期后,脚本直接把新 Session Token 重新写回账号。
请求体字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
accessToken |
string |
是 | 新的 Session Token |
platformUserId |
number |
否 | 覆盖或补充平台用户 ID |
refreshToken |
string |
否 | sub2api 会话可附带 |
tokenExpiresAt |
number | string |
否 | sub2api 会话过期时间戳 |
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/accounts/1/rebind-session" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"accessToken": "session=new-token",
"platformUserId": 1001
}'成功响应示例:
{
"success": true,
"tokenType": "session",
"credentialMode": "session",
"apiTokenFound": true
}如果你要自动化的是 Codex / Claude / Gemini CLI / Antigravity 这类 provider 授权,请使用下面这组接口。
GET /api/oauth/providers
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/oauth/providers" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}"示例响应:
{
"providers": [
{
"provider": "codex",
"label": "Codex",
"platform": "codex",
"enabled": true,
"loginType": "oauth",
"requiresProjectId": false,
"supportsDirectAccountRouting": true,
"supportsCloudValidation": true,
"supportsNativeProxy": true
}
]
}POST /api/oauth/providers/:provider/start
请求体字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId |
string |
否 | 某些 provider 可选传入的项目 ID,例如 Gemini CLI |
proxyUrl |
string | null |
否 | 本次 OAuth 流程使用的显式代理;传 null 可清空继承代理 |
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/oauth/providers/codex/start" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{}'成功响应:
{
"provider": "codex",
"state": "oauth-state-123",
"authorizationUrl": "https://auth.example.com/authorize?...",
"instructions": {
"redirectUri": "http://localhost:1455/auth/callback",
"callbackPort": 1455,
"callbackPath": "/auth/callback",
"manualCallbackDelayMs": 15000
}
}GET /api/oauth/sessions/:state
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/oauth/sessions/oauth-state-123" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}"典型状态包括:
pendingsuccesserror
POST /api/oauth/sessions/:state/manual-callback
当浏览器已经完成授权,但回调没有自动打到 Metapi 时,可以手动提交最终 callback URL。
curl -sS "${METAPI_ADMIN_BASE_URL}/api/oauth/sessions/oauth-state-123/manual-callback" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"callbackUrl": "http://localhost:1455/auth/callback?code=demo&state=oauth-state-123"
}'GET /api/oauth/connections
示例:
curl -sS "${METAPI_ADMIN_BASE_URL}/api/oauth/connections?limit=50&offset=0" \
-H "Authorization: Bearer ${METAPI_AUTH_TOKEN}"| 接口 | 作用 |
|---|---|
POST /api/oauth/connections/:accountId/rebind |
为已有 OAuth 账号重新发起授权 |
DELETE /api/oauth/connections/:accountId |
删除 OAuth 连接 |
当同一个 (platform, url) 已存在时,会返回:
{
"error": "A new-api site with URL https://api.example.com already exists."
}某些 new-api / anyrouter 站点会返回:
{
"success": false,
"needsUserId": true,
"message": "This site requires a user ID. Please fill in your site user ID."
}这时请在 /api/accounts/verify-token 或 /api/accounts 里补上 platformUserId。
{
"success": false,
"invalidUserId": true,
"message": "The provided user ID does not match this token. Please check your site user ID."
}{
"success": false,
"shieldBlocked": true,
"message": "This site is shielded by anti-bot challenge. Create an API key on the target site and import that key."
}这通常意味着账号密码或 Session 流程被防护页拦住了,更适合改用 API Key 模式。
POST /api/accounts/verify-token 对同一来源 IP 有速率限制。超过限制后会返回:
{
"success": false,
"message": "请求过于频繁,请稍后再试"
}建议脚本在这类错误上做退避重试。