Skip to content

Team OAuth 应用 API

Team 工作区开放平台使用的接口。全部接口需要网站 JWT;只读接口允许目标 Team 成员,Product/Client 草稿写入要求绑定 Project write,审核、发布和下架要求 Team Owner/Admin。

插件开发体验者与 Scope 资格

创建者由 Product 的 owner_user_id 表示,固定可见、不可删除且不占体验者名额。插件 Product 可再 添加最多 5 个体验者 UID;加入名单只表示允许进入开发 OAuth,用户仍必须 consent,并且当前仍须是 Team 成员、具备绑定 Project 的显式 execute 或 admin grant,以及满足所申请 Scope 的实时资格。 Project write 不隐式等于 execute,Team Owner/Admin 也不自动获得开发授权资格。

GET /teams/:teamId/oauth-apps/products/:productId/testers

Team 成员读取创建者、5 人上限和体验者当前资格。响应:

json
{
  "success": true,
  "owner_user_id": "创建者 UUID",
  "development_testers": [
    { "user_id": "体验者 UUID", "status": "active" }
  ],
  "tester_limit": 5,
  "can_manage_testers": true
}

status=ineligible 表示 UID 仍占名额,但已失去 Team/Project 资格;管理者应移除后释放名额。

POST /teams/:teamId/oauth-apps/products/:productId/testers

请求体 { "user_id": "UUID" }can_manage_testers 使用与写接口相同的 Project write 资格判定。创建者不能添加为体验者;第六名返回 oauth_development_tester_limit_exceeded,没有 Project execute 资格返回 oauth_development_tester_ineligible

DELETE /teams/:teamId/oauth-apps/products/:productId/testers/:testerUserId

移除后在同一事务消费该用户尚未兑换的 development code,并撤销该 Product 下的 development token。 authorization、exchange、refresh 和运行时仍会复查实时资格。

GET /teams/:teamId/oauth-apps/eligible-scopes

创建 Product 前使用,要求查询参数 project_id,可选 context=development|public(默认 development)。服务端先验证当前用户对该 Team Project 至少有 read,再返回 active + self-service registry 与实际 Project 权限的交集。创建表单只允许从该结果选择 Scope。

GET /teams/:teamId/oauth-apps/products/:productId/eligible-scopes

查询参数 context=development|public,缺省为 development。返回 active + self-service registry 与当前 用户 Team/Project 权限的交集;Client 编辑表单只允许从该结果选择,页面展示、草稿保存和签发都使用 同一规则。资格过期导致保存拒绝时,前端会立即刷新该集合。

审核预检与最近提交快照

http
GET /teams/:teamId/oauth-apps/clients/:clientId/review/precheck

该请求是只读操作:不会创建审核单、占用免费次数、扣除积分或创建计费账户。

路径参数

参数类型说明
teamIdUUIDProduct 所属 Team
clientIdUUID要提交审核的 OAuth Client

成功响应

json
{
  "success": true,
  "precheck": {
    "requires_payment": false,
    "fee_milli_credits": 0
  },
  "latest_submission": {
    "version": "1.2.0",
    "status": "rejected",
    "catalog_metadata": {
      "name": "示例应用",
      "developerName": "示例团队",
      "description": "详细介绍",
      "category": "Productivity",
      "tagline": "一句话介绍"
    }
  }
}

precheck 还会包含本次审核的剩余额度、报价指纹、Owner 余额等实时计费信息,调用方必须使用本次 响应展示确认界面。latest_submission 是该 Client 最新审核单的只读快照;没有历史审核单时为 null。快照只返回 versionstatuscatalog_metadata,不返回图标、截图或插件包文件 ID, 也不能代替当前 Project 文件校验。

常见错误

HTTP 状态错误码说明
403oauth_team_admin_required当前用户不是 Team Owner/Admin
400oauth_app_not_foundClient 不存在或不属于该 Team

客户端应按响应中的稳定错误码映射本地化文案。无法识别的稳定错误码应保留在错误提示中,便于排查, 不要只显示“提交审核失败”。

提交审核

http
POST /teams/:teamId/oauth-apps/clients/:clientId/review

提交体包含语义化版本、Catalog 文案、当前 Project 中的文件引用和本次预检报价。付费审核必须明确 传入 confirm_paid=true 及预检返回的费用和报价指纹;服务端会拒绝过期报价。插件应用必须提交一个 target=universal.reaiapp,网页应用不能提交插件包。

重试同一份提交内容时应复用 Idempotency-Key;只有提交内容发生变化后才生成新 Key,避免网络重试 造成重复审核单或重复扣费。

插件包 Manifest 必须满足 Driver V2 Host 1.1 schema(基线 1.1@c3475cb);审核请求的 artifact target=universal 不等于 Manifest 的 targets 字段,后者是平台/架构对象数组。Schema 不通过时返回 reaiapp_manifest_schema_invalid,并可附带只含 pathkeywordschemaBaseline 的安全 details; 声明 i18n 的包还会校验中英文语言内容、元数据引用和 Build Manifest 全资源完整性。 语言内容不合法仍返回 reaiapp_manifest_schema_invalid(安全路径 /i18n);资源路径、长度、摘要或 ZIP 数据不一致返回 reaiapp_resource_integrity_invalid。未声明 i18n 的历史包继续兼容。 i18n 包展开后单资源限 32 MiB、累计限 64 MiB,分别返回 reaiapp_entry_size_exceededreaiapp_uncompressed_size_exceeded;这些预算在资源解压前检查。 前端详情基线白名单兼容当前值与旧节点的 1.1@8f7fba4,未知基线不可回显。 缺少插件 OAuth 身份返回 reaiapp_oauth_app_id_missing。客户端不得显示服务端未列入白名单的详情字段。

撤回审核

POST /teams/:teamId/oauth-apps/clients/:clientId/reviews/:submissionId/withdraw

撤回该 Team 的一张进行中审核单,仅 Team Owner/Admin 可调用。

路径参数

参数类型说明
teamIdUUIDProduct 所属 Team
clientIdUUID提交审核的 OAuth Client
submissionIdUUID要撤回的审核单

幂等

请求头 Idempotency-Key(≤128 字符,缺省时服务端生成随机值)。同一审核单重复撤回时,只有与 首次请求一致的幂等键才返回幂等结果,否则返回 409。

费用处理

以审核单的 started_at 为结算边界:

  • 审核开始前撤回:免费额度占用恢复(当月已用次数减 1);付费审核费用原路退款。
  • 审核开始后撤回:费用照常结算,不退款。

成功响应

json
{
  "success": true,
  "result": {
    "id": "审核单 UUID",
    "app_id": "Client UUID",
    "product_id": "Product UUID",
    "revision_id": "revision UUID",
    "version": "1.2.0",
    "status": "withdrawn",
    "started_at": null,
    "idempotent": false
  }
}

result 为审核单完整行加 idempotent 标记,示例仅展示部分字段。

常见错误

HTTP 状态错误码说明
403oauth_team_admin_required当前用户不是 Team Owner/Admin
404oauth_app_not_foundClient 不存在或不属于该 Team
404oauth_review_submission_not_found审核单不存在或不属于该 Client/Team
409oauth_review_submission_not_withdrawable审核单不在 queued/pending/in_review 状态
409oauth_review_withdraw_idempotency_conflict已撤回但幂等键与首次请求不一致
422oauth_review_allocation_state_invalid审核额度状态异常,需要人工介入

发布与下架

GET /teams/:teamId/oauth-apps/products/:productId/releases/:releaseId/publish-precheck

在打开发布确认前比较当前公开 revision 与候选 release 的 redirect_urisscopesauthorization_config。仅 Team Owner/Admin 可调用。security_changed=true 表示实际发布时会撤销 该 Client 全部现有 public code/token,用户必须重新授权;false 表示不会因这三项安全 字段批量撤权。current_public_revision_id 同时是本次确认的并发快照;实际发布必须原样带回, 否则服务端拒绝已过期的确认。预检失败时前端不执行发布。

json
{
  "success": true,
  "precheck": {
    "release_id": "release UUID",
    "candidate_revision_id": "candidate revision UUID",
    "current_public_revision_id": "current revision UUID or null",
    "security_changed": true
  }
}

POST /teams/:teamId/oauth-apps/products/:productId/releases/:releaseId/publish

把已审核的 approved|delisted|superseded release 发布为 Product 的当前公开版本,仅 Team Owner/Admin 可调用, 请求体必须带回紧邻本次用户确认的发布预检所返回的 current_public_revision_id(首次发布为 null)。

json
{
  "expected_current_public_revision_id": "current revision UUID or null"
}

发布成功后:

  • Client 的 namedescriptionlogo_urlhomepage_urlredirect_urisscopes 同步为 该 release 冻结的 revision,current_public_revision_id 指向它。
  • 同一 Product 下每个 Client 各自只能有一个 published release;已有公开版本会在同一事务变为 superseded,目标版本与该 Client 的公开 revision 原子切换,不产生下线空窗,也不会替换同一 Product 中其他 Client 的在线版本。列表返回 superseded_by_release_id,前端版本历史会显示它被哪个版本替代。
  • delisted 可重新上架,superseded 历史版本也可作为回滚目标重新发布,不需要重新审核。
  • 与上一公开版本相比安全字段(redirect_urisscopesauthorization_config)有变化时, 公开模式下未消费的授权码与未吊销的 token 全部作废,响应中 security_changedtrue
  • 插件(listing_kind=plugin)release 还要求其插件包 artifact 已是 approved 状态。

成功响应

json
{
  "success": true,
  "release": {
    "id": "release UUID",
    "product_id": "Product UUID",
    "app_id": "Client UUID",
    "submission_id": "审核单 UUID",
    "version": "1.2.0",
    "status": "published",
    "published_at": "2026-08-29T08:00:00.000Z",
    "public_revision_id": "revision UUID",
    "security_changed": false,
    "idempotent": false
  }
}

release 为 release 完整行加 public_revision_idsecurity_changedidempotent,示例仅展示 部分字段。对已发布且公开 revision 一致的 release 重复调用时幂等返回。

常见错误

HTTP 状态错误码说明
403oauth_team_admin_required当前用户不是 Team Owner/Admin
400oauth_product_release_publish_precheck_required缺少或错误填写预检返回的公开 revision 快照
404oauth_product_release_not_foundrelease 不存在或不属于该 Product/Team
409oauth_product_release_publish_precheck_stale确认后公开版本已变化,必须重新预检并再次确认
409oauth_product_release_not_publishablerelease 不是 approved/delisted/superseded、revision 不可发布等
409oauth_product_release_artifact_invalid插件包 artifact 不是 approved 状态
409oauth_review_scope_lock_set_changed_retry并发修改 scope,可直接重试

POST /teams/:teamId/oauth-apps/products/:productId/releases/:releaseId/delist

下架已发布的 release 并停止新授权与分发,仅 Team Owner/Admin 可调用。下架保留审核结果和公开 revision pointer,存量 public token 可继续按原安全合同 refresh;再次调用 publish 即可重新上架。

请求体

字段类型必填说明
reasonstring下架原因(非空,去除首尾空白后不能为空)
json
{
  "reason": "版本存在缺陷,先下架修复"
}

成功响应

json
{
  "success": true,
  "release": {
    "id": "release UUID",
    "product_id": "Product UUID",
    "version": "1.2.0",
    "status": "delisted",
    "delisted_at": "2026-08-29T09:00:00.000Z",
    "delist_reason": "版本存在缺陷,先下架修复",
    "idempotent": false
  }
}

release 为 release 完整行加 idempotent 标记。对已下架的 release 用同一 reason 重复调用时 幂等返回;reason 不同则返回 409。

常见错误

HTTP 状态错误码说明
400oauth_product_release_delist_reason_required缺少 reason 或为空白
403oauth_team_admin_required当前用户不是 Team Owner/Admin
404oauth_product_release_not_foundrelease 不存在或不属于该 Product/Team
409oauth_product_release_not_publishedrelease 不是 published 状态
409oauth_product_release_delist_conflict已下架但 reason 与首次下架不一致

Client 管理

GET /teams/:teamId/oauth-apps/clients/:clientId

读取 OAuth Client 详情与全部 revision,Team 成员即可调用(只读)。

路径参数

参数类型说明
teamIdUUIDClient 所属 Team
clientIdUUIDOAuth Client

成功响应

json
{
  "success": true,
  "client": {
    "id": "Client UUID",
    "product_id": "Product UUID",
    "client_id": "OAuth client_id 字符串",
    "client_label": "Primary",
    "name": "示例应用",
    "team_id": "Team UUID",
    "project_id": "Project UUID",
    "app_type": "standard",
    "current_public_revision_id": null,
    "disabled_at": null,
    "created_at": "2026-08-25T00:00:00.000Z",
    "updated_at": "2026-08-25T00:00:00.000Z"
  },
  "revisions": [
    {
      "id": "revision UUID",
      "app_id": "Client UUID",
      "revision_number": 1,
      "is_draft": true,
      "is_frozen": false,
      "name": "示例应用",
      "redirect_uris": ["https://example.com/callback"],
      "scopes": [],
      "updated_at": "2026-08-25T00:00:00.000Z"
    }
  ]
}

revisionsrevision_number 倒序返回该 Client 的全部 revision(含草稿与冻结版本)。

常见错误

HTTP 状态错误码说明
403oauth_team_member_required当前用户不是该 Team 成员
404oauth_app_not_foundClient 不存在、已删除或不属于该 Team

PATCH /teams/:teamId/oauth-apps/clients/:clientId

保存 Client 草稿(乐观并发控制)。Team 成员须对 Client 所在 Project 有写权限 (Owner/Admin 天然满足,普通成员需项目 write 权限)。

请求体

字段类型必填说明
expected_updated_atstring乐观锁:调用方持有的草稿 updated_at,与服务端不一致即冲突
client_labelstringClient 展示名;提供时必须是字符串
其余字段-草稿字段:namedescriptionlogo_urlhomepage_urlredirect_urisscopesauthorization_configtest_evidence,与创建时同构
json
{
  "expected_updated_at": "2026-08-25T00:00:00.000Z",
  "client_label": "Primary",
  "name": "示例应用",
  "description": "更新后的简介",
  "redirect_uris": ["https://example.com/callback"],
  "scopes": ["<scope>"]
}

成功响应

json
{
  "success": true,
  "draft": {
    "id": "revision UUID",
    "app_id": "Client UUID",
    "revision_number": 1,
    "is_draft": true,
    "is_frozen": false,
    "name": "示例应用",
    "updated_at": "2026-08-29T00:00:00.000Z"
  }
}

draft 为草稿 revision 完整行。安全相关字段(scopesredirect_urisauthorization_config) 发生变化时,该 Client 开发模式下未消费的授权码、票据与未吊销的 token 会全部作废,需重新走开发 授权流程。

常见错误

HTTP 状态错误码说明
400oauth_app_draft_conflict请求体缺少 expected_updated_at
400invalid_oauth_product_client_labelclient_label 存在但不是字符串
403oauth_team_member_required / oauth_project_write_required非团队成员 / 无项目写权限
404oauth_app_not_foundClient 不存在或不属于该 Team
409oauth_app_draft_conflict草稿已在别处被修改,需重新拉取后重试

DELETE /teams/:teamId/oauth-apps/clients/:clientId

删除 OAuth Client(软删除,保留审计记录),仅 Team Owner/Admin 可调用。删除原因固定为 team_admin_delete_client;删除时未消费授权码与未吊销 token 全部作废。

成功响应

json
{
  "success": true,
  "result": {
    "app_id": "Client UUID",
    "deleted": true,
    "consumed_code_count": 2,
    "revoked_token_count": 5,
    "idempotent": false
  }
}

常见错误

HTTP 状态错误码说明
403oauth_team_admin_required当前用户不是 Team Owner/Admin
404oauth_app_not_foundClient 不存在或不属于该 Team
409oauth_app_review_active_withdraw_required存在进行中的审核单,须先撤回

POST /teams/:teamId/oauth-apps/clients/:clientId/development-ticket

为 Client 当前草稿签发一个短期开发模式票据,用于开发自测授权。票据明文只在响应中出现一次, 服务端只保存哈希。调用者必须是创建者或 Product 体验者,并且仍是 Team 成员、对 Client 所在 Project 有显式 execute 或 admin grant;换取授权码时会再次按同一资格规则校验。

请求体

字段类型必填说明
redirect_uristring回调地址,必须是草稿 revision 已登记的 redirect_uris 之一
scopesstring[]申请的 scope 列表,必须是草稿 scopes 的子集且允许自助申请;服务端会去重并排序
json
{
  "redirect_uri": "https://example.com/callback",
  "scopes": ["<scope>"]
}

成功响应

json
{
  "success": true,
  "development_ticket": "票据明文,仅此一次返回",
  "expires_at": "2026-08-29T08:09:55.000Z",
  "result": {
    "ticket_id": "票据 UUID",
    "app_id": "Client UUID",
    "revision_id": "草稿 revision UUID",
    "redirect_uri": "https://example.com/callback",
    "scopes": ["<scope>"],
    "expires_at": "2026-08-29T08:09:55.000Z",
    "idempotent": false
  }
}

票据有效期约 10 分钟(受 development_ticket_ttl_seconds=600 限制,接口实际签发 595 秒), 授权码将绑定草稿 revision。

幂等与限流:

  • 请求头 Idempotency-Key 作为 request_id;同一 key 重复请求返回幂等结果,参数不一致返回 409。
  • 每用户每小时签发次数受限(默认 20 次/小时),超限返回 429。

常见错误

HTTP 状态错误码说明
400oauth_development_ticket_invalid参数不合法、redirect_uri 未登记或 scope 不是草稿子集
403oauth_team_member_required / oauth_project_write_required非团队成员 / 无项目写权限
404oauth_app_not_foundClient 不存在或不属于该 Team
409oauth_development_ticket_idempotency_conflict幂等键重复但请求参数不一致
429oauth_development_ticket_rate_limited命中每小时签发限流

Product 管理与限额

GET /teams/:teamId/oauth-apps/limits

返回 Team OAuth Product 限额与审核计费配置,Team 成员即可调用(只读)。

成功响应

json
{
  "success": true,
  "limits": {
    "max_active_apps": 10,
    "max_products_per_team": 10,
    "create_per_hour": 10,
    "development_tickets_per_hour": 20,
    "free_reviews_per_month": 2,
    "review_fee_milli_credits": 1000000,
    "timezone": "Asia/Shanghai",
    "development_ticket_ttl_seconds": 600
  },
  "active_products": 3,
  "can_manage_reviews": true
}
字段说明
limits来自 site_settingsoauth_app_self_service_limits
active_products该 Team 未删除、ownership_state=assigned 的 Product 数量
can_manage_reviews当前用户是否为 Team Owner/Admin(能否提交/撤回审核)

当前实现要求配置中 max_products_per_team=10free_reviews_per_month=2review_fee_milli_credits=1000000,配置缺失或偏离时返回 503。

常见错误

HTTP 状态错误码说明
403oauth_team_member_required当前用户不是该 Team 成员
503oauth_app_self_service_limits_invalid站点限额配置缺失或不合法

GET /teams/:teamId/oauth-apps/products

一次拉取该 Team 全部 Product 及其 Client、审核单、release,Team 成员即可调用(只读)。

成功响应

json
{
  "success": true,
  "products": [
    {
      "id": "Product UUID",
      "primary_client_id": "Client UUID",
      "owner_user_id": "创建者 UUID",
      "development_tester_user_ids": [],
      "team_id": "Team UUID",
      "project_id": "Project UUID",
      "listing_kind": "plugin",
      "package_app_id": null,
      "first_approved_at": null,
      "created_at": "2026-08-25T00:00:00.000Z",
      "updated_at": "2026-08-25T00:00:00.000Z",
      "clients": [],
      "submissions": [],
      "releases": []
    }
  ]
}
字段说明
products未删除、ownership_state=assigned 的 Product,按创建时间倒序
clients该 Product 下的 Client,按创建时间正序
submissions该 Product 的审核单,按创建时间倒序
releases该 Product 的 release,按批准时间倒序

常见错误

HTTP 状态错误码说明
403oauth_team_member_required当前用户不是该 Team 成员

POST /teams/:teamId/oauth-apps/products

创建 Product 与首个 Client。Team 成员须对目标 Project 有写权限。

请求体

字段类型必填说明
project_idstringProduct 绑定的 Project(须属于该 Team)
listing_kindstring上架类型:webplugin
client_labelstring首个 Client 展示名,默认 Primary(1–80 字符)
namestring应用名(≤120 字节)
descriptionstring简介(≤4000 字节)
logo_url / homepage_urlstring图标与主页 URL
redirect_urisstring[]回调地址列表(≤20 个,不可重复)
scopesstring[]scope 列表(≤32 个,须为允许自助申请的 scope)
authorization_configobject授权配置(序列化后 ≤32768 字节)
test_evidenceobject自测证据(序列化后 ≤65536 字节)
json
{
  "project_id": "Project UUID",
  "listing_kind": "web",
  "client_label": "Primary",
  "name": "示例应用",
  "description": "应用简介",
  "homepage_url": "https://example.com",
  "redirect_uris": ["https://example.com/callback"],
  "scopes": ["<scope>"]
}

client_id 由服务端按 teamId 与创建请求幂等键确定性派生(32 位字符串),不由客户端指定。 请求头 Idempotency-Key(≤128 字符,缺省随机);同一幂等键重复创建返回已有结果,同键不同参数 返回 409。

成功响应

json
{
  "success": true,
  "product": {
    "id": "Client UUID",
    "product_id": "Product UUID",
    "client_id": "确定性派生的 32 位 client_id",
    "draft_revision_id": "草稿 revision UUID",
    "idempotent": false
  }
}

新建返回 201,幂等重放返回 200

常见错误

HTTP 状态错误码说明
400invalid_team_oauth_product_createproject_id/listing_kind 缺失或不合法
400invalid_team_oauth_product_payload草稿字段不合法
403oauth_team_member_required / oauth_project_write_required非团队成员 / 无项目写权限
409oauth_team_product_limit_exceeded超出每 Team Product 上限(默认 10)
409oauth_team_product_create_idempotency_conflict幂等键重复但参数不一致

POST /teams/:teamId/oauth-apps/products/:productId/migrate

把当前用户名下待迁移的历史 Product(ownership_state=legacy_unassigned)显式迁移到该 Team 的 指定 Project,仅 Team Owner/Admin 可调用。GET /teams/:teamId/oauth-apps/legacy-products 返回的待迁移列表即配合此接口使用。

路径参数

参数类型说明
teamIdUUID目标 Team
productIdUUID待迁移 Product

请求体

字段类型必填说明
project_idstring迁移后绑定的 Project(须属于该 Team)

成功响应

json
{
  "success": true,
  "product": {
    "id": "Product UUID",
    "owner_user_id": "用户 UUID",
    "team_id": "Team UUID",
    "project_id": "Project UUID",
    "ownership_state": "assigned",
    "listing_kind": "web",
    "publisher_id": "Team UUID 字符串",
    "primary_client_id": "Client UUID",
    "first_approved_at": null,
    "idempotent": false
  }
}

product 为 Product 完整行加 idempotent 标记,示例仅展示部分字段。重复迁移同一 Product 到 同一 Team/Project 时幂等返回。

常见错误

HTTP 状态错误码说明
400oauth_product_project_binding_invalid缺少 project_id 或 Project 不属于该 Team
403oauth_team_admin_required当前用户不是 Team Owner/Admin
403oauth_legacy_product_owner_required只有 Product owner 本人可发起迁移
403oauth_product_cross_team_transfer_forbiddenProduct 已归属其它 Team,禁止跨 Team 转移
404oauth_product_not_foundProduct 不存在或已删除
409oauth_team_product_limit_exceeded迁移会超出每 Team Product 上限

POST /teams/:teamId/oauth-apps/products/:productId/move-project

把 Product 移到同 Team 的另一个 Project,仅 Team Owner/Admin 可调用。仅允许在首次审核批准 (first_approved_at)之前移动,之后锁定。

请求体

字段类型必填说明
project_idstring新 Project(须属于该 Team)

成功响应

json
{
  "success": true,
  "product": {
    "id": "Product UUID",
    "project_id": "新 Project UUID",
    "idempotent": false
  }
}

product 为 Product 完整行加 idempotent 标记,示例仅展示部分字段。移动到当前所在 Project 时 幂等返回。

常见错误

HTTP 状态错误码说明
400oauth_product_project_binding_invalid缺少 project_id 或 Project 不属于该 Team
403oauth_team_admin_required当前用户不是 Team Owner/Admin
404oauth_product_not_foundProduct 不存在或不属于该 Team
409oauth_product_project_locked已首次批准,Project 绑定锁定

POST /teams/:teamId/oauth-apps/products/:productId/listing-kind

切换 Product 的上架类型(web/plugin),仅 Team Owner/Admin 可调用。存在进行中审核 (queued/pending/in_review)或已发布 release 时锁定。

请求体

字段类型必填说明
listing_kindstring目标类型:webplugin

成功响应

json
{
  "success": true,
  "product": {
    "id": "Product UUID",
    "listing_kind": "plugin",
    "idempotent": false
  }
}

product 为 Product 完整行加 idempotent 标记,示例仅展示部分字段。切换到当前类型时幂等返回。

常见错误

HTTP 状态错误码说明
400oauth_product_listing_kind_invalidlisting_kind 不是 web/plugin
403oauth_team_admin_required当前用户不是 Team Owner/Admin
404oauth_product_not_foundProduct 不存在或不属于该 Team
409oauth_product_listing_kind_locked审核进行中或已有发布版本,类型锁定

POST /teams/:teamId/oauth-apps/products/:productId/clients

为已存在的 Product 增加一个 OAuth Client。Team 成员须对 Product 所在 Project 有写权限。

路径参数

参数类型说明
teamIdUUIDProduct 所属 Team
productIdUUID目标 Product

请求体

字段类型必填说明
client_labelstringClient 展示名(1–80 字符)
namestring应用名(≤120 字节)
其余字段-与创建 Product 相同的草稿字段(descriptionlogo_urlhomepage_urlredirect_urisscopesauthorization_configtest_evidence

client_id 同样由服务端按 Team、Product 与幂等键确定性派生。请求头 Idempotency-Key (≤128 字符,缺省随机);同键不同参数返回 409 oauth_product_client_idempotency_conflict

成功响应

json
{
  "success": true,
  "client": {
    "id": "Client UUID",
    "product_id": "Product UUID",
    "client_id": "确定性派生的 client_id",
    "client_label": "备用 Client",
    "draft_revision_id": "草稿 revision UUID",
    "idempotent": false
  }
}

常见错误

HTTP 状态错误码说明
400invalid_oauth_product_client_create缺少 client_label 或草稿字段不合法
403oauth_team_member_required / oauth_project_write_required非团队成员 / 无项目写权限
404oauth_product_not_foundProduct 不存在、已删除或不属于该 Team

GET /teams/:teamId/oauth-apps/legacy-products

返回当前用户名下待迁移的历史 Product(ownership_state=legacy_unassigned),配合 POST /teams/:teamId/oauth-apps/products/:productId/migrate 使用。Team 成员即可调用;结果按 当前用户过滤,与 Team 内其他成员无关。

成功响应

json
{
  "success": true,
  "products": [
    {
      "id": "Product UUID",
      "primary_client_id": "Client UUID",
      "owner_user_id": "当前用户 UUID",
      "created_at": "2026-01-01T00:00:00.000Z",
      "updated_at": "2026-01-01T00:00:00.000Z",
      "name": "示例应用",
      "clients": [
        {
          "id": "Client UUID",
          "product_id": "Product UUID",
          "client_id": "OAuth client_id 字符串",
          "client_label": "Primary",
          "name": "示例应用"
        }
      ]
    }
  ]
}

name 取主 Client(primary_client_id)的应用名,找不到时为 null。Product 按创建时间倒序, Client 按创建时间正序。

常见错误

HTTP 状态错误码说明
403oauth_team_member_required当前用户不是该 Team 成员

发布者身份与数量限制

产品列表响应包含 publisher_idpublisher_id_source。来源为 team_id 时,值就是产品所属团队的 Team ID, 不是所有者 User ID;official_reserved 表示现有保留身份 reai。以 API 返回的实际值填入插件 app.manifest.jsonpublisherId,不要由项目 ID 或产品 ID 推导。开放平台应用卡片、详情与审核弹窗均提供复制。

限额响应新增 product_limit_exempt:仅站点 site:admin 管理员为 true,创建及迁移产品不受应用数量上限约束。 团队管理员身份本身不构成豁免;开发权限、审核流程与费用不变。

月度审核记录

GET /teams/:teamId/oauth-apps/review-history?month=2026-09&page=1&settlement_page=1

响应新增 campaign(state、started_at、ended_at、reward_milli)与 settlements(page、page_size、total、records)。 settlement_page 独立控制到账记录页,范围1–10000,每页20条。到账记录按实际结算月份筛选,包含 release_id/product_id/app_name/version/team_id/team_name/settled_at/refund_milli/reward_milli/refund_transaction_ids/reward_transaction_id。 退款与首次奖励分开显示,团队仅能看进入自己团队的款项。原 summary/records 仍按提交月份计算。 GET /teams/:teamId/oauth-apps/limits 同时在 limits.launch_campaign 返回活动状态;状态查询失败会报错,不能当成活动未开始。

仅 Team Owner/Admin 可访问。省略 month 时使用服务器按 Asia/Shanghai 计算的当前自然月; month 必须是 YYYY-MM,page 为 1–10000 的整数,每页 20 条。响应 history 包含月份、时区、分页总数、 summaryrecords。摘要对整月汇总,不受当前页影响:

  • free_used / free_remaining:团队共享免费额度的当前占用/剩余;free_returned 为原月份已返还次数。
  • paid_count:不含已退款的收费次数。
  • charged_milli_credits / refunded_milli_credits / net_milli_credits:实际扣款、退款和净支出(1000 milli-credits = 1 积分)。
  • 明细包含冻结应用名称、版本、Product/Project ID、提交时间、审核状态、funding_typebilling_status、实际金额及退款时间。

每月团队共享两次免费审核,用完后每次 1000 积分,从 Team Owner 的团队积分余额扣除。 只有成功提交才计次或扣款;开始审核前撤回返还原月份免费额度或退款,开始审核后撤回不返还。 已删除应用的历史消费仍保留。

付费预检在余额缺失或分项不一致时返回 balance_not_found / balance_inconsistent,不会再伪装为报价过期。 没有有效 paid_confirmation.fingerprint 时,客户端不得允许付费提交。真正的报价变化仍要求重新获取报价并重新确认。

包身份/版本不匹配响应可包含白名单详情 {field, expected, actual};客户端按字段匹配及长度/字符限制展示, 不得显示额外内部详情。审核提交/上传错误持续留在弹窗内,由用户手动关闭;全站错误消息也不再自动消失。

应用管理的审核筛选与分组

开放平台应用管理提供「全部 / 未审核 / 已审核 / 已驳回」筛选,数量按完整应用列表统计。 默认排序为按审核分组:未审核、已驳回、已审核。前两组默认展开,已审核默认收起;点击组标题控制整组卡片。 选择具体分类或更新时间正/倒序时改为完整卡片平铺。组内最近更新在前,切换筛选和排序会保留组展开状态,刷新或切换团队则重置。

展示直接使用现有 GET /teams/:teamId/oauth-apps/productsclientssubmissionsreleases,没有新增接口参数:

  • 每个当前 Client 取 created_at 最近的审核记录;queuedin_reviewwithdrawn 或无提交归未审核,approved 归已审核,rejectedcancelled 归已驳回。
  • 取消仍显示「审核已取消」和处理原因;disabled_at 非空的 Client 有单独停用提示。
  • 多客户端产品按未审核 → 已驳回 → 已审核的优先级汇总。无提交时仅对应 Client 的 release 可证明已审核。
  • 审核分类不等同于发布状态;旧版已上线不会覆盖新版待审,已下架也不等于审核驳回。已删除 Client 的历史记录不参与展示计算。
  • 更新时间取产品、当前 Client、审核活动和 release 审核/上线/下架的最大有效时间,同时间按产品 ID 稳定排序。

这些规则仅用于列表展示,不能作为审核、发布或权限判断依据。原有管理按钮与计费/奖励流程保持原有服务端校验。

AI Workflow Editor