# 概览 Source: https://developer.screenshare.cn/ # 把查端流程接入你的应用 Screenshare API 为服务器插件、机器人和 Partner 管理后台提供稳定的查端记录、邀请、工单进度和服务权益接口。Webhook 在业务变化时通知你的接收端。 **生产地址:`https://api.screenshare.cn/v1`** · 当前版本:v1 ## 从这里开始 1. 在 [个人中心的 API & Webhooks](https://www.screenshare.cn/profile) 生成密钥。 2. 阅读 [快速开始](/quickstart/) 并调用 `GET /v1/me`,确认凭证绑定的组织和权限。 3. 有多个组织时,先完成 [多组织接入](/multi-organization/) 的凭证映射。 4. 按 [一次性邀请链接](/invitations/) 实现生成、分发、玩家认领和结果同步。 5. 配置 [Webhook](/webhooks/),在工单及查端记录变化时获取通知。 ## v1 能做什么 | 能力 | 个人密钥 | 组织密钥 | | --- | --- | --- | | 精确查询公开 USS 查端记录 | `public:read` | `public:read` | | 查询个人服务权益 | `entitlements:read` | 不支持 | | 查询绑定组织的记录 | 不支持 | `records:read` | | 生成、读取、取回和撤销邀请 | 不支持 | `invitations:read` / `invitations:write` | | 查询组织工单进度 | 不支持 | `tickets:read` | | 查询绑定组织的权益 | 不支持 | `entitlements:read` | | 订阅组织业务事件 | 在个人中心另行配置,须具有该组织的管理员成员身份 | 同左 | 组织密钥只绑定一个组织。账号同时管理多个组织时,应创建不同密钥。Admin、SSer 等站点角色不会自动给予第三方应用跨组织访问权。 ## 人和 AI 都能读取 - [OpenAPI JSON](/openapi.json):请求参数、响应字段、认证和错误结构。 - [llms.txt](/llms.txt):供 AI 查找文档的索引。 - [llms-full.txt](/llms-full.txt):完整纯文本手册。 - 每篇文档均提供原始 Markdown 下载,所有示例使用虚构数据。 ## 范围与边界 v1 提供工单**进度**,包括状态和消息数量。它不开放工单正文、远程设备密码、附件下载、联系方式、内部查端备注、账号安全资料或后台管理操作。自动处理详细会话、支付、成员管理和 OAuth 用户授权不在本次版本范围内。 “未找到记录”不等于“查端通过”;历史通过记录也只描述相应查端时间的结论。接入方应保留结果时间,并处理后续更正和删除事件。 --- # 快速开始 Source: https://developer.screenshare.cn/quickstart/ # 快速开始 本教程使用生产 API。密钥只应保存在你控制的服务器或插件服务端配置中。不要写入网页 JavaScript、客户端模组、公开仓库或日志。 ## 1. 创建密钥 打开 [个人中心](https://www.screenshare.cn/profile),切换到 **API & Webhooks → 生成密钥**。 - 名称:建议填写应用和部署用途,如“生存服查端机器人”。 - 授权归属:选择“个人”或一个你实际担任管理员的有效组织。 - 权限:仅勾选应用需要的权限。 - 有效期:选择“指定天数”(1–365 天,默认 90 天)或“永久有效”;个人和组织密钥都支持。 - 生成:登录后点击“生成并显示密钥”,无需再次输入账户密码或两步验证码。 完整密钥只在创建成功时显示一次。丢失后只能撤销并重新生成。 永久密钥的 `/v1/me` 响应中 `expires_at` 为 `null`,表示没有自动到期时间。撤销、账号停用、密码变更和组织授权失效仍会使密钥失效,调用也仍受同样的频率与总量限制。此设置不会延长一次性邀请链接的 7 天有效期。 ## 2. 设置环境变量 以下命令中的值是占位符。请通过自己的密钥管理系统安全注入实际密钥。 ```bash export SCREENSHARE_API_KEY='YOUR_SERVER_SIDE_API_KEY' export SCREENSHARE_PARTNER_ID='YOUR_PARTNER_ID' ``` PowerShell 对应使用 `$env:SCREENSHARE_API_KEY` 和 `$env:SCREENSHARE_PARTNER_ID`。不要在共享终端或可记录输入的演示环境粘贴生产密钥。 ## 3. 检查凭证 ```bash curl --fail-with-body https://api.screenshare.cn/v1/me \ -H "Authorization: Bearer $SCREENSHARE_API_KEY" ``` 成功响应示例: ```json { "ok": true, "data": { "key_id": "11111111-1111-4111-8111-111111111111", "account_id": "22222222-2222-4222-8222-222222222222", "partner_id": "33333333-3333-4333-8333-333333333333", "scopes": ["invitations:write", "invitations:read", "tickets:read"], "expires_at": "2026-12-24T00:00:00.000Z" }, "request_id": "req_44444444-4444-4444-8444-444444444444" } ``` 启动时检查 `partner_id` 是否等于服务端配置,检查所需权限是否包含在 `scopes` 中。不匹配时停止该组织的调用,并交由管理员更新配置。 ## 4. 生成一个邀请 请为每次业务上的新邀请生成新的随机请求编号,并把它连同组织 ID 和请求正文持久化。网络超时或服务返回 5xx 后,使用**原编号、原密钥和原正文**重试。 ```bash curl --fail-with-body -X POST \ "https://api.screenshare.cn/v1/partners/$SCREENSHARE_PARTNER_ID/invitations" \ -H "Authorization: Bearer $SCREENSHARE_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: 74e123d0-53f0-47dd-a2ef-678513162c44' \ --data '{"game":"minecraft","notes":"请配合本次服务器查端。"}' ``` 成功响应中的 `data.link` 是发给玩家的完整邀请地址。必须保留 `#token=...` 部分;不要把这个链接写入公共日志。保存 `data.id` 作为邀请 ID。 ## 5. 让玩家自行完成认领 玩家打开链接、填写游戏 ID、联系方式、远程信息及所需备注后加入。预览链接不占用名额。第一个完整提交成功的浏览器获得会话凭证;不能用 API 代替玩家认领。 收到 `invitation.joined` 通知后,用事件里的 `invitation_id` 查询 [工单进度](/tickets/)。查端记录生成后,处理 `record.created` 并读取记录详情。 ## 在本地先验证集成 仓库中的 [本地模拟服务](/examples/mock-server.mjs) 提供合成数据,可验证请求和错误分支。它不代表生产认证,也不会创建真实工单。当前没有生产 `test key` 或独立沙箱域名;实际调用生成邀请会创建真实的组织邀请,但不会因此扣除查端次数。 --- # 认证与权限 Source: https://developer.screenshare.cn/authentication/ # 认证与权限 ## API Key 公开 API 使用请求头认证: ```http Authorization: Bearer uss_live_<64位随机十六进制字符> ``` 不要把密钥放在查询参数、请求正文或 URL 中。浏览器登录 Cookie 不能替代 API Key,API 也不会给第三方创建网站登录会话。只使用 HTTPS 原始地址,客户端不要跟随重定向后继续转发密钥。 `GET /v1/health` 不需要密钥。其他 v1 接口都需要有效密钥。`GET /v1/me` 不要求额外业务权限,可用于确认当前凭证。 ## 权限矩阵 | Scope | 可调用的能力 | 个人密钥 | 组织密钥 | | --- | --- | --- | --- | | `public:read` | 精确 USS 记录查询 | 是 | 是 | | `entitlements:read` | 密钥所属个人或组织的权益 | 个人权益接口 | 绑定组织权益接口 | | `records:read` | 组织记录列表、筛选和详情 | 否 | 是 | | `invitations:read` | 组织邀请列表和状态 | 否 | 是 | | `invitations:write` | 新建、取回完整链接、撤销未使用邀请 | 否 | 是 | | `tickets:read` | 已加入工单的列表和进度 | 否 | 是 | 读写权限互不隐含。只有 `invitations:write` 的密钥可以新建邀请,但不能调用邀请列表;需要两种能力时应同时选择两个 scope。取回完整邀请链接属于写权限范围,因为该链接本身是可分发的加入凭证。 ## 谁可以创建 - 所有有效账号都可以创建个人密钥。 - 组织密钥和 Webhook 需要账号是对应有效组织的 `manager` 成员。 - 普通组织成员不能创建组织 API 凭证;他们原有的网页邀请和工单操作权限保持不变。 - 全局 Admin 或 SSer 必须同时是该组织的实际管理员成员,才能通过此开发者平台获取组织凭证。 - 凭证由创建者在自己的个人中心管理;其他账号不能查看其完整密钥或撤销接口中的凭证。 ## 实时失效与永久撤销 个人和组织密钥均可选择 1–365 天有效期或“永久有效”,默认仍为 90 天。在已登录的个人中心生成 API Key 无需再次验证账户密码或两步验证码;创建 Webhook 的验证流程见 [Webhook 接入](/webhooks/)。 `GET /v1/me` 的 `expires_at` 是 ISO 8601 时间或 `null`。`null` 仅表示密钥没有自动到期时间,客户端不要将其转换为日期、显示为已过期或据此跳过错误处理。网站密钥列表也显示“永久有效”。有期限的现有密钥保持原到期时间;需要永久密钥时,请创建新密钥并按下方步骤轮换。 服务器每次请求检查密钥有效期(若设置)、撤销状态、账号状态以及当前组织管理员身份。以下变更会永久撤销相关密钥(包括永久密钥),并停用相应 Webhook: | 变更 | 影响 | | --- | --- | | 从组织移除或从管理员降为普通成员 | 该账号绑定该组织的密钥及回调 | | 组织归档 | 绑定该组织的密钥及回调 | | 账号停用 | 该账号的全部密钥及回调 | | 修改或重置密码 | 该账号的全部密钥及回调 | 恢复组织、重新加入或重新启用账号不会恢复旧凭证。请重新创建并部署。普通网页退出登录不会撤销长期 API Key。 ## 轮换 1. 创建相同组织、相同或更小权限的新密钥。 2. 调用 `/v1/me` 验证新凭证。 3. 更新应用的服务端配置,并确认正常调用。 4. 撤销旧密钥。 邀请幂等记录以密钥为作用域。在恢复一个结果不确定的创建请求时,先用原密钥完成恢复;不要立即换新密钥并重复创建。 每个账号最多保留 20 把尚未到期且未撤销的密钥,永久密钥同样计入。永久密钥与有期限密钥使用相同的权限、组织边界、调用限额和审计规则。密钥仅保存不可逆摘要,完整值不会再次提供。 API Key 有效期与邀请链接、服务权益的有效期互相独立。永久密钥不会产生永久邀请、免费次数或无限调用额度。 --- # 多组织接入 Source: https://developer.screenshare.cn/multi-organization/ # 多组织接入 一个 Screenshare 账号可以属于多个组织,并在不同组织中拥有不同角色。API 的授权上下文始终由**密钥绑定组织 + URL 中的组织 ID + 当前成员权限**共同决定。 ## 显式绑定,禁止猜测 假设同一个账号是组织 A 的管理员、组织 B 的管理员、组织 C 的普通成员: | 组织 | 可创建组织密钥 | 可用该密钥访问 | | --- | --- | --- | | A | 是 | A 的记录、邀请、工单和权益,仍受 scope 限制 | | B | 是 | B 的相应能力 | | C | 否 | 不可因同账号管理 A/B 而获取 C 的 API 权限 | 用 A 的密钥请求 `/v1/partners/B/invitations` 会返回 `403 PARTNER_SCOPE_MISMATCH`。即使创建者同时是 B 的管理员,也不会自动切换。 ## 推荐配置模型 在你自己的后台建立“服务器 → 组织 ID → 密钥引用”映射。密钥引用指向环境变量或密钥存储,不直接放在用户可下载的配置中。 ```json { "servers": { "survival": {"partner_id":"ORGANIZATION_A_ID","key_env":"SCREENSHARE_KEY_A"}, "minigames": {"partner_id":"ORGANIZATION_B_ID","key_env":"SCREENSHARE_KEY_B"} } } ``` 启动时对每份配置调用 `/v1/me`,严格比较返回的 `partner_id`。不要选择组织列表中的第一个组织,不要使用“最近使用的组织”,不要以组织名称代替 ID。 ## 一次邀请的业务记录 在调用创建接口**之前**持久化: | 字段 | 用途 | | --- | --- | | `local_request_id` | 你自己的业务主键 | | `server_id` | 发起请求的服务器 | | `partner_id` | 明确选定的组织 | | `credential_reference` | 使用哪份密钥配置,不是完整密钥 | | `idempotency_key` | 本次调用及所有恢复重试使用的编号 | | `request_body` | 规范化后的 game 和 notes | | `invitation_id` | API 成功返回后保存 | | `ticket_id` | 玩家加入后返回的正式工单 ID | 普通插件玩家不能任意传入 `partner_id` 后就以你的管理员密钥创建邀请。先在你自己的应用中验证操作人的管理员权限,再从可信配置选择组织。 ## Webhook 也要按组织分开 每个回调只绑定一个组织并拥有独立签名密钥。多组织应用可以共用接收服务,但建议使用不同路径,如 `/hooks/screenshare/org-a` 和 `/hooks/screenshare/org-b`,以便先按接收配置选择签名密钥。 先验证签名,再信任载荷的 `partner_id`,并核对它与当前回调配置相符。不要根据尚未验签的 `partner_id` 自动选择生产密钥或执行操作。 ## 成员权限变化 创建者失去某个组织管理员身份时,该组织相关凭证立即失效,其他组织凭证不受此成员变更影响。接收方应将 `401` 或 `403` 标记为“需要管理员修复凭证”,停止自动重试授权失败,并暂停相应组织的自动任务。 --- # 请求与响应约定 Source: https://developer.screenshare.cn/conventions/ # 请求与响应约定 ## 地址与版本 所有业务接口位于 `https://api.screenshare.cn/v1`。不要调用主站或 Dashboard 的内部 `/api/...` 路径;它们使用网站会话或内部服务授权,不属于开放协议。 请求 JSON 使用 UTF-8 和 `Content-Type: application/json`。邀请正文最大 4096 字节(无 Content-Length 的流式正文也检查),读取期限为 5 秒;不接受压缩正文。撤销邀请不发送请求体。路径最多 512 字符,查询字符串最多 2048 字符。仅使用已公开参数,不重复传入同名参数,不在 URL 传递凭证。 当前服务端接口面向服务端集成,不提供跨域浏览器调用;不要在前端暴露 API Key 来绕过这一边界。 ## 响应信封 ```json {"ok":true,"data":{"example":"value"},"request_id":"req_UUID"} ``` ```json {"ok":false,"error":{"code":"INSUFFICIENT_SCOPE","message":"需要 records:read 权限。"},"request_id":"req_UUID"} ``` 根据 HTTP 状态和 `error.code` 编写逻辑,`message` 供人阅读。每个 API 响应都包含 `X-Request-Id`;请求支持时请提供此编号。响应使用 `Cache-Control: no-store`,客户端不要把受组织权限保护的响应放进共享缓存。 时间采用 ISO 8601,正常输出 UTC `Z`。所有 ID 都应视为不透明字符串;不要推断时间、顺序或权限。只有公开查端记录的 `uuid` 使用明确的 USS 格式。 ## 分页 - 组织记录使用 `limit`(1–100,默认 20)和 `cursor`。按 `updated_at`、`id` 升序返回;`next_cursor` 为 `null` 时结束。 - 邀请与工单列表使用 `page`(1–10000,默认 1),每页 20 条,返回 `page_count`。 - 翻页期间保持相同筛选条件。记录列表是实时视图,不是冻结快照;并发修改可能令条目移动。客户端按记录 ID 去重,并用重叠时间窗口同步。 - 邀请列表以创建时间倒序,新邀请可能导致页面移动。完整同步时按邀请 ID 去重。 ## 限流 | 范围 | 限制 | | --- | --- | | 每把有效 API Key | 60 次/分钟,5,000 次/天 | | 同一创建账号的所有 API Key | 300 次/分钟,20,000 次/天 | | 同一组织的全部 API Key(包括不同管理员创建的密钥) | 300 次/分钟,20,000 次/天 | | 创建邀请的请求(组织共享,包括幂等重试) | 10 次/分钟,60 次/小时,200 次/天 | | 邀请及工单接口合计(组织共享,包括链接取回、撤销) | 60 次/分钟 | | 邀请及工单接口正在处理的请求 | 每把密钥 2 个、每组织 4 个、每账号 6 个 | | 来源 IP 的边缘保护(包括健康接口) | 约 30 次/10 秒,180 次/分钟 | | 凭证的边缘保护(包括格式有效但不存在的凭证) | 约 20 次/10 秒,60 次/分钟 | 账号、密钥、组织的基础配额由共享数据库原子检查,跨边缘位置生效,不会因更换 IP 或增加密钥而重置。分钟、小时和日配额采用固定窗口;日配额在 **UTC 00:00(北京时间 08:00)** 重置。业务成功与失败请求都计入已通过的配额;某层拒绝后不再执行后续业务。创建邀请重试同样受限,不能通过不断更换幂等编号绕过限制。 边缘保护是按 Cloudflare 位置执行的近似计数,用于在数据库查询前拦截突发流量;不是全局精确配额。另有每边缘位置约 3,000 次/分钟的整体认证保护,降低大量不同凭证冲击数据库的风险。边缘阈值可能先于业务配额触发;生产限流设施不可用时返回 `503 RATE_LIMIT_UNAVAILABLE`,不会自动取消保护。 达到配额返回 `429 RATE_LIMITED`,同时处理太多工单请求则返回 `429 CONCURRENCY_LIMITED`。以响应中的 **Retry-After 秒数** 为准,不要固定等待 60 秒;日配额耗尽时可能需要等待至次日。并发限制通常返回 2 秒。收到 503 时也应遵守服务端给出的重试时间。 通过基础配额检查的响应携带以下请求时刻的快照;有并发调用时不保证后续仍有同样额度: | 响应头 | 含义 | | --- | --- | | `X-RateLimit-Limit` | 当前策略的窗口最大次数 | | `X-RateLimit-Remaining` | 本次检查后剩余次数 | | `X-RateLimit-Reset` | 窗口结束时间,Unix 秒 | | `X-RateLimit-Policy` | 正常为 `key-minute`;拒绝时说明触发策略,例如 `organization-day`、`invitation-hour`、`ticket-concurrency` | | `Retry-After` | 至少等待的秒数,仅需重试指导的响应提供 | 业务配额拒绝时,前三个头描述触发的配额。边缘或并发拒绝只保证提供策略名称及 Retry-After,可能没有额度数字。 客户端为每个组织安排共享任务队列,每把密钥同时最多发起 2 个工单请求。优先用 Webhook 同步;状态核对通常以 30–60 秒或更长间隔进行。429 后暂停对应组织/账号的任务,加入少量随机延迟后恢复;不要切换 IP、账号或密钥继续刷请求。 ### 个人中心与 Webhook 操作 | 操作 | 共享限制 | | --- | --- | | 查看 API 设置或投递列表 | 每账号 30 次/分钟 | | 配置修改(创建、验证、重发等) | 每账号 10 次/分钟、60 次/小时、200 次/天 | | 撤销 API Key / 停用 Webhook | 独立的每账号 10 次/分钟,不受上述修改的小时和日配额阻挡 | | 创建 API Key | 每账号 20 次/小时、50 次/天;最多 20 把未到期有效密钥 | | 创建 Webhook | 每账号 5 次/小时、20 次/天;每账号及每组织最多 10 个未停用回调 | | 验证或测试回调 | 同一回调 1 次/分钟;每账号 3 次/分钟、30 次/小时;每组织 60 次/小时 | | 手动重发 | 同一回调 5 次/分钟;每账号 10 次/小时;每组织 20 次/小时;同一投递 3 次/天 | 个人中心还在会话及审计读取前执行来源 IP 边缘保护:约 30 次/10 秒、60 次/分钟。上述限制不会赋予原本没有的组织权限。 ### 限流日志 正常进入业务处理的请求保留脱敏调用日志。已识别密钥的限流拒绝每把密钥每分钟最多保存一条样本,ID 以 `rate_` 开头;边缘拦截和无效凭证不逐条写入业务数据库。个人中心调用统计因此不是被拦截流量的完整计费计数;平台 HTTP 429 指标用于观察整体拒绝量。这避免攻击者利用日志本身放大存储开销。 ## 网络故障与幂等 GET 可以在网络错误、超时、429、502、503、504 时进行有限次数重试,使用退避和少量随机延迟。401/403 不应持续自动重试。 新建邀请要求 `Idempotency-Key`。其格式为 16–128 位 ASCII 字母、数字、`_` 或 `-`,推荐随机 UUID。相同密钥、组织、编号和规范化正文再次提交返回同一邀请。正文变化返回 `409 IDEMPOTENCY_CONFLICT`。 首次创建返回 201;重放返回 200,`data.replayed=true`。请求编号不会因为邀请加入、撤销或到期而重新用于新邀请;需要新邀请时使用新编号。网络错误不代表服务器没有创建成功。 ## 兼容性 同一 v1 版本可增加可选字段和新的错误码。忽略不认识的响应字段;处理未知枚举时采用保守分支。现有字段的含义或授权范围若发生不兼容变化,会通过版本更新说明。调用方不要把某次返回字段的排列顺序作为协议。 --- # 查端记录 Source: https://developer.screenshare.cn/records/ # 查端记录 ## 标识符不要混用 - `uuid`:站内 USS 查端记录标识,如 `USS-20260925-ABCDEF123456`。不是 Minecraft/Mojang 账号 UUID,不证明账号所有权。 - `id`:记录的数据库资源 ID,用于组织详情接口。 - `player_name`:本次记录中的玩家名称;不能假定名称唯一或长期不变。 ## 公开精确查询 ```http GET /v1/records/{uuid} Authorization: Bearer YOUR_API_KEY ``` 需要 `public:read`。`uuid` 必须是完整 `USS-YYYYMMDD-12位字母数字` 格式,比较时忽略大小写。不提供公开玩家名称搜索、模糊查询或公开全量枚举。 ```json { "ok": true, "data": { "id":"b2222222-2222-4222-8222-222222222222", "uuid":"USS-20260925-ABCDEF123456", "player_name":"ExamplePlayer", "game_category":"Minecraft", "game":"Example Server", "checked_at":"2026-09-25T03:00:00.000Z", "result":"clean", "result_label":"通过", "checker_name":"ExampleChecker", "public_notes":"本次查端公开说明。", "updated_at":"2026-09-25T03:05:00.000Z" }, "request_id":"req_EXAMPLE" } ``` | result | 含义 | | --- | --- | | `clean` | 本次查端通过 | | `warning` | 可疑痕迹或警告,不应当作作弊的同义词 | | `cheating` | 本次记录结论为作弊 | 未找到返回 `404 RECORD_NOT_FOUND`;格式不正确返回 `422 INVALID_RECORD_UUID`。 ## 组织记录列表 ```http GET /v1/partners/{partner_id}/records?limit=20 ``` 需要组织密钥和 `records:read`。仅返回绑定组织的记录,字段与公开记录对象相同;组织内部备注和 SSer 备注不会因此开放。 | 参数 | 类型 | 说明 | | --- | --- | --- | | `limit` | integer | 1–100,默认 20 | | `cursor` | string | 使用上次返回的 `next_cursor`,作为不透明值 URL 编码 | | `updated_after` | ISO 8601 | 包含该时间起发生更新的记录,使用 `>=` 比较 | | `result` | enum | clean / warning / cheating | | `game` | enum | minecraft / fps | | `player_name` | string | 1–120 字符,完整名称精确匹配,忽略大小写 | ```json {"ok":true,"data":{"items":[],"next_cursor":null},"request_id":"req_EXAMPLE"} ``` 空列表是成功结果,不是 404。未知筛选参数返回 422。Minecraft 对应 Minecraft 分类;其余受支持的查端游戏在此 API 中归入 fps 服务类别。 ## 组织记录详情 ```http GET /v1/partners/{partner_id}/records/{record_id} ``` 需要 `records:read`。返回一个记录对象。该记录不存在或不属于此组织时统一返回 `404 RECORD_NOT_FOUND`。 ## 增量同步与更正 1. 首次遍历列表并以 `id` 保存记录。 2. 后续使用 `updated_after`,保留几分钟重叠窗口,按 ID 和更新时间合并。 3. 收到 `record.updated` 后重新请求详情,以最新数据替换原值。 4. 收到 `record.deleted` 后移除本地记录的可见性。它也可能代表记录被转移到其他组织;事件不会透露目标组织。 5. 定期完整核对:更新游标无法单独发现被删除的记录,Webhook 也有重试上限。 不要基于旧记录永久推断玩家当前状态。显示查端时间、结果来源和更正时间。删除后的记录详情可能立即返回 404,这是正常同步分支。 --- # 一次性邀请链接 Source: https://developer.screenshare.cn/invitations/ # 一次性邀请链接 这是 Partner 接入查端流程的入口。你的服务端为**明确选定的组织**生成邀请,玩家在 Screenshare 页面自行提交资料。正式会话使用现有组织工单系统。 ## 完整流程 1. 验证你自己系统中的操作人有权为目标服务器发起查端。 2. 根据服务器配置选择 `partner_id` 和绑定该组织的密钥,使用 `/v1/me` 验证映射。 3. 持久化业务请求和随机 `Idempotency-Key`,调用创建邀请。 4. 保存返回的邀请 ID,将完整 `link` 私下发送给目标玩家。 5. 玩家打开链接;预览不会占位,也不会生成正式工单。 6. 玩家填写游戏 ID、联系方式、完整远程信息,以及未预填的备注。 7. 第一次完整有效提交原子认领邀请。并发提交只会有一个成功者。 8. 收到 `invitation.joined` 或通过状态查询确认 `joined`,再查询工单进度。 9. 工作人员完成查端、归档记录;接收记录事件并查询结果。 ## 创建邀请 ```http POST /v1/partners/{partner_id}/invitations Authorization: Bearer YOUR_ORGANIZATION_KEY Content-Type: application/json Idempotency-Key: 74e123d0-53f0-47dd-a2ef-678513162c44 {"game":"minecraft","notes":"请配合本次服务器查端。"} ``` 需要 `invitations:write`。`partner_id` 必须与密钥绑定组织一致。 | 字段 | 必填 | 规则 | | --- | --- | --- | | `game` | 是 | `minecraft` 或 `fps` | | `notes` | 否 | 可省略或空字符串;非空时为 2–600 字符,去除首尾空白 | 不接受 `holderId`、玩家 Cookie、远程密码、任意扣费账号、有效期或目标组织等额外字段。有效期由平台固定为创建后 7 天,每个组织最多保留 50 个有效待加入/处理中邀请。 ```json { "ok":true, "data":{ "id":"8f86690d-76d7-4e87-84d2-27b5fc8b6d41", "game":"minecraft", "state":"pending", "ticket_id":null, "created_at":"2026-09-25T03:00:00.000Z", "expires_at":"2026-10-02T03:00:00.000Z", "archived_at":null, "link":"https://dash.screenshare.cn/partner-ticket/ORGANIZATION_ID/8f86690d-76d7-4e87-84d2-27b5fc8b6d41#token=EXAMPLE_TOKEN", "replayed":false }, "request_id":"req_EXAMPLE" } ``` 首次成功为 HTTP 201。相同请求重放返回 200 和 `replayed:true`;如果邀请已经被使用、过期或撤销,重放仍返回原邀请,`link:null`,不会创建新邀请。 ## 查询邀请 ```http GET /v1/partners/{partner_id}/invitations?page=1 GET /v1/partners/{partner_id}/invitations/{invitation_id} ``` 需要 `invitations:read`。列表返回 `data.items`、`data.page`、`data.page_count`,每页 20 条。详情返回单个邀请对象。只返回状态元数据,不返回完整链接、草稿备注或玩家凭证。 | state | 含义 | 接入方处理 | | --- | --- | --- | | `pending` | 尚未认领,且仍在有效期内 | 可以分发或撤销 | | `claiming` | 玩家提交处理中或正在核对结果 | 等待确认,不重复创建工单 | | `joined` | 玩家已成功加入 | 用邀请 ID 查询工单进度 | | `expired` | 未使用邀请超过 7 天 | 需要时用新编号创建新邀请 | | `revoked` | 未使用邀请已被撤销 | 停止分发,旧链接不可用 | `claiming` 不会仅因原有效期到达就变成可重新使用的邀请;平台先核对上游结果,防止重复工单。 ## 取回链接 ```http GET /v1/partners/{partner_id}/invitations/{invitation_id}/link ``` 需要 `invitations:write`。仅未认领且未到期的有效邀请可返回 `data.link`;否则为 `409 INVITE_UNAVAILABLE`。只具有读权限的应用不能获取加入凭证。 URL 片段 `#token=...` 必须完整保留。不要把链接放进短链接分析服务、公开群日志或第三方统计参数。玩家加入后页面会清除片段中的密钥。 ## 撤销 ```http POST /v1/partners/{partner_id}/invitations/{invitation_id}/revoke Authorization: Bearer YOUR_ORGANIZATION_KEY ``` 需要 `invitations:write`,不需要请求正文。未使用邀请可以撤销;重复撤销同一已撤销邀请返回相同状态。`claiming` 和 `joined` 状态不能通过撤销接口删除或关闭工单。 ## 幂等与结果不确定 幂等作用域是 **密钥 ID + 组织 ID + Idempotency-Key**。同一作用域下,`game` 或规范化后的 `notes` 改变,返回 `409 IDEMPOTENCY_CONFLICT`。邀请认领后草稿备注会被清除,但服务器仍保存不可逆请求指纹用于冲突检测。 客户端连接超时、未收到完整响应或收到 5xx 时,保留原请求编号和正文继续恢复。不要为了消除错误直接生成新编号,否则会产生多份真实邀请。旧密钥轮换后不继承幂等作用域。 ## 玩家身份和浏览器凭证 玩家不需要注册 Screenshare 账号。成功认领后,访问凭证保存在认领浏览器的安全 HttpOnly Cookie 中,最长 90 天。更换浏览器或清除数据后,不能凭已使用的一次性链接重新认领。组织管理员无法通过开放 API 读取、复制或重置玩家 Cookie。 工单以独立访客身份存在,不会因为玩家填了与网站用户名相同的游戏 ID 就归入该账号个人工单。已登录玩家可使用头像快照,但这不是账号所有权认证。 ## 次数规则 生成邀请、预览、玩家加入、查询和回复不会额外扣除 Partner 查端次数。工作人员归档实际查端记录时,按现行组织规则消耗相应游戏的服务次数。邀请 API 不会给组织增加额度,也不保证未来归档时仍有可用额度。 普通个人查端工单仍按个人规则计次,不能通过伪造 Holder 或目标组织改变计费归属。 --- # 工单进度 Source: https://developer.screenshare.cn/tickets/ # 工单进度 v1 支持只读组织工单进度,使用 `tickets:read`。只处理通过组织一次性邀请创建的工单,不开放个人工单或工作人员全局队列。 ## 已加入工单列表 ```http GET /v1/partners/{partner_id}/tickets?page=1 ``` 每页 20 条,按邀请创建时间倒序。返回 `data.items` 中的邀请元数据,且仅包含 `state=joined` 的邀请。每项的 `id` 为邀请 ID,`ticket_id` 为正式工单 ID;详情状态需要单独查询。 列表不是所有历史类型工单的全站目录,也不提供消息正文。组织网页中归档的已加入邀请仍可以出现在历史列表中,`archived_at` 会标记整理时间。 ## 工单详情 ```http GET /v1/partners/{partner_id}/tickets/{invitation_id} ``` **路径末段使用邀请 ID,不是正式工单 ID。** 邀请 ID 是组织隔离和持久工单定位所使用的公开标识。 ```json { "ok":true, "data":{ "id":"FORMAL_TICKET_ID", "invitation_id":"8f86690d-76d7-4e87-84d2-27b5fc8b6d41", "partner_id":"ORGANIZATION_ID", "game":"minecraft", "status":"open", "created_at":"2026-09-25T03:00:00.000Z", "updated_at":"2026-09-25T03:10:00.000Z", "message_count":3 }, "request_id":"req_EXAMPLE" } ``` | status | 含义 | | --- | --- | | `open` | 等待工作人员处理或回复 | | `waiting_user` | 等待用户或发起方回应 | | `resolved` | 工单已解决 | 尚未加入时返回 `409 PLAYER_NOT_JOINED`。邀请不存在、属于其他组织或工单关联校验失败时,不会返回会话内容。 ## 工单关闭不等于查端通过 `resolved` 只描述会话状态。它不能推导出 `clean`、`warning` 或 `cheating`。查端结果以 [记录接口](/records/) 返回的正式记录为准。 v1 事件中的工单 ID 与记录 ID 是不同命名空间。当前没有可供第三方依赖的一对一自动关联字段;不要通过相似名字或时间擅自认定某条记录属于某个工单。应用需要明确关联时,应在自己的业务流程中由授权人员确认记录 UUID。 ## 同步建议 优先接收 `invitation.joined`、`ticket.message.created`、`ticket.status.updated`。收到事件后重新读取进度,以最新状态为准。通知可能重复或乱序;`message_count` 是当前可见的非系统消息数量,不应被当作严格单调递增的业务流水号。 没有 Webhook 时,可每 30–60 秒查询正在处理的工单,给请求加入随机偏移,并遵守所有密钥合计限额。已解决工单降低轮询频率。API 不提供会话回复、关闭、重开、附件或远程信息操作。 --- # 服务权益 Source: https://developer.screenshare.cn/entitlements/ # 服务权益 ## 个人权益 ```http GET /v1/entitlements ``` 需要个人密钥和 `entitlements:read`。只返回密钥创建账号自己的权益。组织密钥调用此接口返回 `403 PERSONAL_KEY_REQUIRED`。 ## 组织权益 ```http GET /v1/partners/{partner_id}/entitlements ``` 需要绑定该组织的密钥和 `entitlements:read`。 ```json { "ok":true, "data":{ "owner_type":"partner", "owner_id":"ORGANIZATION_ID", "games":[ {"game":"minecraft","remaining_units":18,"unlimited":false,"total_units":40,"used_units":22,"expires_at":"2026-10-25T00:00:00.000Z","next_starts_at":null}, {"game":"fps","remaining_units":0,"unlimited":false,"total_units":0,"used_units":0,"expires_at":null,"next_starts_at":null} ] }, "request_id":"req_EXAMPLE" } ``` | 字段 | 含义 | | --- | --- | | `remaining_units` | 当前有效权益的剩余计次数之和 | | `unlimited` | 当前是否存在不限次数权益;为 true 时不能仅用 remaining_units 判断可用性 | | `total_units` | 当前有效计次权益的总次数 | | `used_units` | 当前有效权益关联的实际使用数,不包含已退回使用 | | `expires_at` | 当前权益最早到期时间;存在永久有效权益或没有有效权益时可能为 null | | `next_starts_at` | 已排队权益的最近开始时间,没有则为 null | `expires_at:null` 不等于拥有永久免费服务。必须同时查看 `unlimited`、`remaining_units` 和实际有效权益状态。没有任何额度时仍成功返回两个游戏条目,计数为 0。 ## 时间与扣次 个人已购买次数按当前业务规则长期有效;组织续订可能排队到当前周期结束后开始。当前返回值只描述查询时刻的有效汇总,不把未开始的未来额度加进当前余额。 此接口没有授予、修改、退款或支付能力,也不返回购买者身份、订单数据或管理员内部原因。额度查询与后续实际扣次之间可能发生变化,因此它只能用于显示和提醒;最终能否完成计次以平台执行实际操作时为准。 组织额度授予、调整、使用及周期开始/结束时可触发 `entitlement.updated`。收到事件后重新查询本接口,不要从通知中直接计算余额。 --- # Webhook 接入 Source: https://developer.screenshare.cn/webhooks/ # Webhook 接入 Webhook 把组织业务变化发送到你的 HTTPS 接收端。回调只携带必要的资源 ID 和状态,具体记录由 API 按组织权限读取。 ## 配置流程 1. 部署一个公网 HTTPS 接收端,仅使用默认 443 端口。 2. 在个人中心 **API & Webhooks → 添加回调** 中选择组织、名称、地址和事件。 3. 验证账号密码和已启用的 2FA。保存只显示一次的 `whsec_...` 签名密钥。 4. 将密钥放进接收端服务端环境变量,部署下述验证处理逻辑。 5. 点击 **验证并启用**。平台发送 `webhook.verification`;接收端先验签,再原样返回挑战值。 6. 验证通过后才开始投递新的业务事件。使用“发送测试”确认你的日志和告警链路。 每账号和每组织各最多 10 个未停用的回调,组织额度由所有管理员共享。每个回调只绑定一个组织;只能由该组织的实际管理员创建。停止或轮换时,创建并验证新回调,更新接收配置,再停用旧回调。创建、验证、测试与重发还受[操作频率限制](/conventions/)约束。 ## 地址限制 只允许完整 HTTPS 域名地址,禁止 HTTP、非 443 端口、IP 字面量、用户名/密码、URL 片段、本地及保留域名、本站域名。每次验证和投递均重新检查 DNS 的公网地址;回调不会跟随 HTTP 重定向,也不会转发站点 Cookie、API Key 或内部服务凭证。 第三方机器人平台的普通消息 Webhook 往往不支持本协议的挑战和验签;请先部署你自己的接收服务,再由它调用机器人平台。 ## 请求头与签名 ```http Content-Type: application/json User-Agent: Screenshare-Webhooks/1.0 X-Screenshare-Event-Id: evt_EXAMPLE X-Screenshare-Timestamp: 1790305200 X-Screenshare-Signature: v1=<64位小写十六进制HMAC> ``` 签名算法是 HMAC-SHA256。密钥是创建时显示的**完整 `whsec_...` 字符串的 UTF-8 字节**,不要去掉前缀,不要把后面的十六进制字符先解码成二进制。 签名输入: ```text timestamp + "." + 原始HTTP请求体字节 ``` 接收端应: 1. 限制请求体大小,例如 64 KiB。 2. 读取原始 body,在 JSON 解析或重新序列化之前计算签名。 3. 校验时间戳为整数 Unix 秒,建议允许与当前时钟相差不超过 300 秒。 4. 对十六进制签名进行固定长度校验后,使用恒定时间比较。 5. 解析 JSON,确认 body.id 等于 `X-Screenshare-Event-Id`,partner_id 与此接收配置一致。 6. 按事件 ID 持久化去重,处理成功或可靠入队后返回 2xx。 重试会保留相同事件 ID 和业务载荷,时间戳和签名会重新生成。不要用签名作为业务去重键。 ## 验证接收端 ```json { "id":"evt_EXAMPLE", "type":"webhook.verification", "api_version":"v1", "partner_id":"ORGANIZATION_ID", "created_at":"2026-09-25T03:00:00.000Z", "data":{"challenge":"RANDOM_CHALLENGE"} } ``` 先完成正常验签,再返回 HTTP 200 和如下 JSON,响应不超过 1024 字节: ```json {"challenge":"RANDOM_CHALLENGE"} ``` 仅返回 200 而没有正确挑战值不会启用回调。`webhook.test` 不需要回显挑战,验签后返回 2xx 即可。 ## 重试、重发与顺序 业务事件持久化后进入投递队列,后台约每分钟处理。每次 HTTP 投递超时为 8 秒。任何非 2xx(包括 3xx)和连接错误都会视为失败。 最多自动尝试 8 次。前七次失败后分别等待至少 1 分钟、5 分钟、15 分钟、1 小时、3 小时、6 小时、12 小时,再进行下一次尝试。实际时间受调度和队列负载影响。 最终失败后,可在个人中心的“投递记录”手动重发。已送达事件也可重发;因此必须正确处理重复事件。不同事件不保证按业务发生顺序送达,同一事件可能因确认丢失而再次投递。 每条投递每日最多手动重发 3 次;账号和组织也有共享重发限制。后台每轮最多启动 10 次业务投递,并发最多 3 个,失败只按上述有限次数退避,防止失效接收端和重复点击放大外发流量。 推荐先把事件 ID 和载荷写入你自己的数据库或可靠队列,提交成功后立即响应,再异步执行耗时业务。不要先返回 200 再仅保存在进程内存中。 ## 日志与权限 界面显示最近 50 条业务投递,包括事件 ID、状态、尝试次数和 HTTP 结果。验证和测试不计入业务投递列表。业务投递及 API 调用日志按 30 天保留策略清理。 每次投递会重新检查创建账号、组织状态和当前管理员成员资格。失权或停用后,尚未发送的投递会取消;已经到达接收端的数据无法撤回,正在发送的请求也可能先于撤销完成。 Webhook 适合及时通知,不能代替定期 API 核对。外部工单存储与事件入队是不同服务,极端中断或最终失败时仍可能遗漏通知;接收方应保留低频的状态核对任务。 --- # 事件目录 Source: https://developer.screenshare.cn/events/ # 事件目录 ## 公共信封 ```json { "id":"evt_EXAMPLE", "type":"record.created", "api_version":"v1", "partner_id":"ORGANIZATION_ID", "created_at":"2026-09-25T03:00:00.000Z", "data":{"record_id":"RECORD_ID"} } ``` `created_at` 为业务事件时间,签名头的时间为本次投递时间。所有 ID 都作为不透明字符串保存,不能假定一定是 UUID。尤其工单事件 ID 可能包含多个片段。 ## 业务事件 | 事件 | 触发条件 | data | | --- | --- | --- | | `record.created` | 组织新增查端记录,或记录转入本组织 | `record_id` | | `record.updated` | 本组织记录更新,包括结果更正 | `record_id` | | `record.deleted` | 记录删除或离开本组织 | `record_id` | | `invitation.joined` | 一次性邀请成功加入正式工单 | `ticket_id`, `invitation_id`, `status` | | `ticket.message.created` | 组织工单新增用户或工作人员消息 | `ticket_id`, `invitation_id`, `status` | | `ticket.status.updated` | 工单发生关闭、重开、分配等系统操作 | `ticket_id`, `invitation_id`, `status` | | `entitlement.updated` | 组织权益授予、变更、计次或周期边界 | `game` | 工单消息事件也可能意味着 `open`/`waiting_user` 状态发生变化,因此这两种工单事件都应触发最新进度读取。系统操作不保证每次都会改变状态值。 ```json { "id":"evt_ticket_EXAMPLE", "type":"invitation.joined", "api_version":"v1", "partner_id":"ORGANIZATION_ID", "created_at":"2026-09-25T03:00:00.000Z", "data":{ "ticket_id":"FORMAL_TICKET_ID", "invitation_id":"8f86690d-76d7-4e87-84d2-27b5fc8b6d41", "status":"open" } } ``` ## 验证和测试事件 - `webhook.verification`:data 为 `{ "challenge": "..." }`,必须回显。 - `webhook.test`:data 为 `{ "message": "Screenshare webhook test" }`,验签后响应 2xx。 这两种事件不需要在订阅列表中勾选,分别由验证和测试操作触发。 ## 不应作出的假设 - 不会发送历史积压给刚启用的订阅,先完成初始数据同步。 - 事件载荷不包含查端结论正文、玩家远程信息或联系方式。 - `record.deleted` 不表示玩家无记录或已通过,它表示本组织应停止使用原本可见的该条记录。 - 一次业务动作可能产生多个事件。例如记录归档同时消耗次数时,可能同时产生 `record.created` 和 `entitlement.updated`。 - 消息时间和事件数量不等于扣次数量;按权益接口读取实际剩余值。 - 直接在外部工单存储中作出的操作,不应假定都有对外 Webhook;本版本覆盖网站处理流程中的事件。 --- # 错误与排障 Source: https://developer.screenshare.cn/errors/ # 错误与排障 开放 API 的错误格式始终以 HTTP 状态和 `error.code` 为准。请记录 `request_id`、接口模板和状态码;不要记录 Authorization、完整邀请链接或远程信息。 | HTTP | code | 原因与处理 | | --- | --- | --- | | 400 | `HTTPS_REQUIRED` | 使用正确 HTTPS 地址;不要先把密钥发给 HTTP 再等待跳转 | | 400 | `INVALID_JSON` | JSON 缺失、格式错误或不是对象 | | 400 | `CREDENTIALS_IN_URL` | 移除 URL 凭证,使用 Authorization;已经进入日志的密钥应撤销 | | 400 | `BODY_NOT_ALLOWED` | 撤销邀请不要发送正文 | | 400 | `IDEMPOTENCY_KEY_REQUIRED` | 创建邀请缺少合法请求编号 | | 401 | `INVALID_API_KEY` | 密钥缺失、错误、到期或被撤销;检查个人中心,停止盲目重试 | | 403 | `INSUFFICIENT_SCOPE` | 当前密钥未授权该能力;由管理员重新创建所需范围的凭证 | | 403 | `PARTNER_SCOPE_MISMATCH` | URL 中的组织与密钥绑定组织不同 | | 403 | `PARTNER_MANAGER_REQUIRED` | 创建者已不具备对应有效组织管理员身份 | | 403 | `PARTNER_ACCESS_FORBIDDEN` | 工单桥接重新检查时发现组织或密钥授权已失效 | | 403 | `PERSONAL_KEY_REQUIRED` | 组织密钥调用了个人权益接口 | | 404 | `RECORD_NOT_FOUND` | 记录不存在或不属于此组织;不能解释为通过 | | 404 | `INVITE_UNAVAILABLE` | 邀请不存在或不可见 | | 404 | `TICKET_NOT_FOUND` | 工单不存在或关联校验失败 | | 404 | `NOT_FOUND` | 未开放的路径或方法 | | 409 | `IDEMPOTENCY_CONFLICT` | 同一请求编号对应的正文不同;查明原业务请求,不要自动换编号 | | 409 | `PLAYER_NOT_JOINED` | 邀请尚未形成正式工单 | | 409 | `INVITE_UNAVAILABLE` | 链接已使用、失效、撤销或状态已变化 | | 409 | `PARTNER_INACTIVE` | 组织已归档或不支持当前操作 | | 408 | `REQUEST_TIMEOUT` | JSON 正文未在 5 秒内读取完成;发送完整的小型请求体 | | 413 | `BODY_TOO_LARGE` | 请求超过允许字节数 | | 414 | `QUERY_TOO_LONG` | 查询字符串超过 2048 字符 | | 414 | `PATH_TOO_LONG` | 路径超过 512 字符 | | 415 | `JSON_REQUIRED` | JSON 请求的 Content-Type 不正确 | | 415 | `CONTENT_ENCODING_UNSUPPORTED` | 不接受压缩请求体 | | 431 | `AUTH_HEADER_TOO_LONG` | Authorization 头超过 256 字符 | | 422 | `INVALID_RECORD_UUID` | USS 记录 UUID 格式不正确 | | 422 | `INVALID_GAME` | game 不为 minecraft 或 fps | | 422 | `INVALID_FIELD` | 字符串长度或字符不合法 | | 422 | `UNKNOWN_FIELD` / `UNKNOWN_PARAMETER` | 发送了不支持的 JSON 字段或记录筛选参数 | | 422 | `DUPLICATE_PARAMETER` | 同一查询参数被重复传入 | | 422 | `INVALID_LIMIT` / `INVALID_PAGE` / `INVALID_CURSOR` | 分页参数错误 | | 422 | `INVALID_DATE` / `INVALID_RESULT` | 时间或结果筛选格式错误 | | 429 | `RATE_LIMITED` | 遵守 Retry-After 并退避 | | 429 | `CONCURRENCY_LIMITED` | 同一密钥、组织或账号的工单请求正在处理中,排队后重试 | | 429 | `TOO_MANY_INVITES` | 组织已有 50 个有效待加入/处理中邀请,先处理或撤销旧邀请 | | 503 | `TICKET_SERVICE_UNAVAILABLE` | 工单服务暂不可用,稍后有限重试 | | 503 | `RATE_LIMIT_UNAVAILABLE` | 流量保护暂不可用,按 Retry-After 重试,不要绕过保护 | | 500 | `INTERNAL_ERROR` | 保留 request_id,有限重试后联系支持 | 工单服务也可能返回更具体的 `KOOK_RATE_LIMITED` 等上游错误码。不要在程序中只允许上表列出的错误;为未知 4xx 和 5xx 提供安全分支。 ## 创建邀请时超时 保留原 API Key、组织、Idempotency-Key 和正文重试。响应恢复后保存邀请 ID。不要根据连接超时就把业务状态写成“没有创建”,也不要重新收费或为同一业务连续生成新邀请。 ## 个人中心错误 个人中心使用网站会话,错误展示可能使用 `code`、`message` 顶层字段,这是网站内部协议。第三方只应实现开放 API 的 `error` 信封。 常见配置错误包括 `INVALID_PASSWORD`、`INVALID_TWO_FACTOR`、`INVALID_SCOPES`、`INVALID_EXPIRY`、`KEY_LIMIT`、`WEBHOOK_LIMIT_OR_ACCESS_CHANGED`。 ## Webhook 失败 - `CHALLENGE_RESPONSE_INVALID`:接收端未返回有效且足够小的 JSON。 - `CHALLENGE_MISMATCH`:challenge 没有原样回显。 - `HTTP_3xx`:回调发生重定向,请填写最终 HTTPS 地址。 - `HTTP_4xx`:检查路由、验签原始字节、时钟和请求体大小限制。 - `HTTP_5xx`:接收端处理失败,平台会重试业务事件。 - `INVALID_WEBHOOK_URL` / `UNSAFE_WEBHOOK_DESTINATION`:地址或 DNS 未通过公网目标检查。 - `CONNECTION_FAILED` / `WEBHOOK_UNREACHABLE`:DNS、TLS、网络或超时问题。 - `ACCESS_REVOKED`:回调创建者已失权或订阅已停用,待投递被取消。 支持定位时提供事件 ID、投递状态和 request_id,不要把 API Key 或 Webhook 签名密钥发送给支持人员。 --- # 安全与上线检查 Source: https://developer.screenshare.cn/security/ # 安全与上线检查 ## 凭证保管 API Key 授予持有者对应能力。保存在服务端密钥管理系统或受限制的环境变量中;避免在浏览器、移动客户端、玩家可下载模组、错误堆栈和聊天记录中出现。将日志中的 Authorization 头和 `#token=` 邀请片段清除。 Webhook 密钥与 API Key 是两种不同凭证:前者只用于验证通知签名,后者用于请求 API。不要交换用途,也不要把 API Key 作为回调验证密钥。 ## 最小权限 - 只展示结果的机器人通常只需要 `public:read` 或 `records:read`。 - 只生成邀请的服务可使用 `invitations:write`;需要查看认领状态时加 `invitations:read`。 - 显示工单状态增加 `tickets:read`;显示剩余次数增加 `entitlements:read`。 - 每个组织、每个独立部署使用不同凭证,便于归属和撤销。 - 不让普通用户通过传入任意组织 ID 驱动一个全权后台代理。 ## 平台防刷与客户端责任 平台在认证查询前做边缘突发限制,再原子检查密钥、账号、组织的分钟及每日共享配额。邀请创建有额外的分钟、小时、日配额;工单桥接有并发上限和超时。凭证变更、Webhook 验证、测试及重发有独立限制。具体阈值和响应头以[限流说明](/conventions/)为准。 请求体、路径、查询和分页都有大小上限;不接受 URL 凭证、重复或未知查询参数、压缩请求体。限流错误合并采样,避免一条恶意请求引出多条永久日志。Webhook 仍要求接收端所有权验证、公网 HTTPS、每次 DNS 检查、禁止重定向、签名及有限重试。 这些保护约束业务处理及存储放大,不能保证所有流量都在 Worker 调用前被拦截,也不是云平台费用的硬上限。接入方仍应在自己的入口验证操作人、限制玩家触发频率,并用有界队列、退避和凭证撤销应对异常。 ## 数据处理 公开接口不意味着每项业务数据都可以无限复制。组织接口返回的是该组织授权范围内的数据。业务结束或权限撤销后,应依照自己的授权和数据管理要求清理不再需要的副本。 用户提供的公开备注、玩家名称等仍是不可信文本。网页展示时转义,机器人输出时防止提及所有人或格式注入,不把它们拼进 SQL、命令行或 AI 系统指令。 不要仅凭名字匹配就自动封禁玩家,也不要把 `warning` 转成 `cheating`。保留人工复核能力,并同步记录更正和删除。 ## Webhook 接收端 按原始字节验签;校验时间戳;按事件 ID 持久化去重;严格核对组织。返回 2xx 前确保业务事件已处理或可靠入队。失败时返回非 2xx,让平台重试。 如果已返回 2xx 后还需要后台处理,必须使用自己的持久队列。示例中的 SQLite 收件箱适合单实例演示;多实例部署应使用共享数据库,并让收件箱写入和业务状态更新具备事务或可靠幂等语义。 ## 上线前逐项验证 1. `/v1/me` 中的组织 ID 与应用配置一致。 2. A 组织密钥请求 B 组织时收到 403,且应用不会自动换组织。 3. 缺少 scope 时显示可理解的授权错误。 4. 使用同一请求编号重试邀请不会多开,改变正文会收到 409。 5. 密钥撤销、过期及创建者失去组织管理员身份时,应用停止对应任务。 6. Webhook 错误签名、过期时间戳、错误组织和重复事件都有测试。 7. 模拟接收端 500 和超时,确认重试不会重复执行业务动作。 8. 处理结果更正、删除、工单重开以及未找到记录。 9. 配置定期核对与失败告警,日志中不包含凭证或完整邀请链接。 ## 凭证泄漏 立即在个人中心撤销对应密钥或停用回调,检查最近调用和投递记录,创建替代凭证并重新部署。修改密码会撤销该账号全部开发者凭证;正常轮换单个集成时,可以只撤销相关密钥。 --- # 代码示例 Source: https://developer.screenshare.cn/examples/ # 代码示例 以下文件可以下载后在你自己的服务端运行。均使用环境变量,不包含真实密钥。 | 示例 | 下载 | 环境 | | --- | --- | --- | | API 客户端与创建邀请 | [client.mjs](/examples/client.mjs) | Node.js 22+ | | API 客户端 | [client.py](/examples/client.py) | Python 3.11+,标准库 | | Java 插件服务端调用 | [ScreenshareExample.java](/examples/ScreenshareExample.java) | Java 17+ | | 验签与 SQLite 收件箱 | [webhook-server.mjs](/examples/webhook-server.mjs) | Node.js 24+ | | Python 验签函数 | [verify_webhook.py](/examples/verify_webhook.py) | Python 3.11+,标准库 | | 本地合成 API | [mock-server.mjs](/examples/mock-server.mjs) | Node.js 22+ | ## JavaScript 调用 ```bash node client.mjs me node client.mjs invite minecraft YOUR_PERSISTED_IDEMPOTENCY_KEY ``` 环境变量为 `SCREENSHARE_API_KEY` 和 `SCREENSHARE_PARTNER_ID`。创建邀请时务必传入事先保存的随机请求编号;示例不会在每次重试时自动换编号。 示例不会在终端打印完整邀请链接。结果需要发送给玩家时,由你的应用从返回对象中读取 `data.link`,在经过授权的私密通道分发。 ## Python ```bash python client.py ``` 输出 `/v1/me` 的凭证元数据。`screenshare()` 可由你自己的服务端导入。遇到错误会返回 HTTP 状态和结构化错误;不要把包含 Authorization 的完整请求对象写入异常日志。 ## Java ```bash javac ScreenshareExample.java java ScreenshareExample ``` 展示标准库 HttpClient、超时和禁止重定向。使用插件后台执行器运行 HTTP 请求,不要阻塞 Minecraft 主服务器线程。正式应用可使用自己已有的 JSON 库解析响应。 ## Webhook 接收示例 ```bash export SCREENSHARE_WEBHOOK_SECRET='YOUR_FULL_whsec_SECRET' export SCREENSHARE_PARTNER_ID='YOUR_PARTNER_ID' node webhook-server.mjs ``` 服务监听本机 8080,请通过你控制的公网 HTTPS 443 反向代理接入。示例先验签和核对组织,再将业务事件写入 SQLite 收件箱后响应 204。验证事件在验签后回显 challenge。收件箱不是完整业务系统;需要接入你的持久任务处理器。 ## 本地模拟 ```bash node mock-server.mjs ``` 模拟服务监听 `127.0.0.1:4180`,只接受假密钥 `Bearer test-local-only`。它提供 `/v1/me`、邀请创建的幂等及冲突分支、模拟 429 和模拟记录未找到。测试时单独使用本地配置,不要把生产密钥传给模拟服务,也不要把本地地址配置成生产 Webhook。 --- # AI 接入指南 Source: https://developer.screenshare.cn/ai-guide/ # AI 接入指南 本页是给代码助手和自动开发工具的明确约束。应同时读取 [OpenAPI](/openapi.json)、[完整手册](/llms-full.txt) 和 [一次性邀请流程](/invitations/)。不要根据本站网页内部请求猜测未公开接口。 ## 不变约束 1. 唯一公开生产根地址是 `https://api.screenshare.cn/v1`。 2. 使用 Bearer API Key;密钥只存在服务端,不使用网站 Cookie 或用户密码调用业务 API。 3. 一把组织密钥只绑定一个组织。读取 `/v1/me` 并严格比较 partner_id。 4. 组织授权要求创建者当前为该组织有效的实际 manager 成员,Admin/SSer 不构成跨组织豁免。 5. 创建邀请必须预先持久化 Idempotency-Key、组织、密钥引用和规范化正文。重试保持不变。 6. 邀请是玩家自行进入的页面。不得伪造访客 Cookie、远程信息或跳过首次完整提交。 7. 邀请 ID、正式工单 ID、记录 ID 和 USS UUID 是不同标识,不能互换。 8. 工单详情路径使用 invitation_id。status=resolved 不是查端结论。 9. 公开记录只允许完整 USS UUID 精确查询。没有公开按玩家名枚举的接口。 10. 404 RECORD_NOT_FOUND 不等于 clean;warning 不等于 cheating。 11. Webhook 必须先按原始 body 验签、检查时间,再解析并核对组织;按事件 ID 持久化去重。 12. 事件通知可能重复、乱序或遗漏,保留低频 API 核对流程。 13. 不实现本版本未公开的付款、权限提升、会话内容、附件、账号管理或自动结果写入接口。 14. 按[限流协议](/conventions/)处理动态 Retry-After,不硬编码 60 秒;配额按组织和创建账号共享,轮换密钥不能增加组织额度。 15. 每把密钥最多并发 2 个工单请求;创建邀请重试保留原编号,遇到日配额耗尽应持久化待办,不能循环换编号或立即重试。 16. `/v1/me.expires_at` 可为 `null`,表示个人或组织密钥不自动到期;不要把 null 当作无效日期。永久密钥仍受撤销、实时授权与全部限流规则约束;邀请的 `expires_at` 仍是实际到期时间。 ## 建议模块 ```text server configuration -> organization credential map -> startup /v1/me validation authorized command -> persisted request + idempotency key -> create invitation -> private player link verified webhook -> durable inbox -> fetch latest resource periodic reconcile -> merge by resource ID -> user-facing status ``` 在多租户应用中,每个本地租户必须先匹配到可信的组织配置。不得允许未经授权的请求自由指定密钥引用。接收事件时,不信任未验签的 partner_id 来决定访问哪个组织。 ## 最低测试用例 - 密钥缺失、无效、撤销、过期及权限不足。 - 相同账号管理 A/B,但 A 的密钥不能访问 B。 - 同一幂等编号同正文重放成功,改正文返回冲突。 - 玩家并发认领后只有一个正式工单。 - 邀请到期、已使用、撤销和 claiming 中间状态。 - Webhook 原始字节签名、大小写、时间窗口、错误组织、重复投递、重试。 - 记录更新/移出组织/删除后的本地同步。 - 远程密码、邮箱、联系方式和内部备注不出现在 API 结果或应用日志。 ## 生成代码时的输出要求 明确列出所需 scopes、环境变量、使用的组织配置、持久化字段、重试策略和日志脱敏方案。引用对应文档页和 OpenAPI operationId。没有已公开字段时,写明需要人工确认或产品扩展,不凭空生成数据关联。 --- # 版本与变更记录 Source: https://developer.screenshare.cn/changelog/ # 版本与变更记录 ## v1 永久密钥与文档标识更新 · 2026-09-25 - 个人和组织 API Key 新增“永久有效”,生成时无需再次输入账户密码或两步验证码。 - `/v1/me` 的 `expires_at` 支持 `null`,表示不自动到期;现有有期限密钥保持原期限。 - 永久密钥仍计入 20 把有效密钥上限,并遵守权限、撤销和防刷规则;一次性邀请仍为 7 天。 - 开发者文档页眉与浏览器图标统一使用 Undefined SS 社区 Logo。 ## v1 防刷保护更新 · 2026-09-25 - 新增来源 IP/凭证突发保护、跨密钥和管理员的组织共享配额、每日总量及邀请创建专项限制。 - 新增工单桥接并发限制、配置读取与凭证创建频率限制、Webhook 组织数量和测试/重发配额。 - 动态 `Retry-After` 与 `X-RateLimit-*` 响应头;限流设施异常时保护性返回 503。 - 有界请求体读取、未知/重复参数和 URL 凭证拒绝、超限调用日志采样。 接入程序应按[请求与响应约定](/conventions/)处理限流,不能依赖旧的固定 60 秒重试值。 ## v1 · 2026-09-25 初始版本开放: - 个人及单组织 API Key,有限有效期、权限范围、撤销和调用日志。 - `/v1/me` 凭证检查与 `/v1/health` 健康接口。 - USS 公开记录精确查询、组织记录列表与详情。 - 组织一次性邀请创建、分页查询、状态、取回链接与撤销。 - 已加入组织工单列表和只读进度。 - 个人及组织服务权益汇总。 - 组织 Webhook,接收端验证、HMAC 签名、重试和手动重发。 - OpenAPI、完整 Markdown、AI 索引和可运行示例。 本版本不提供 OAuth 用户授权、公开模糊玩家搜索、工单正文和附件、自动结果写入、支付或成员管理。 文档描述 v1 的实现协议。生产发布状态与域名可用性以实际接口响应为准;可先访问 [健康接口](https://api.screenshare.cn/v1/health)。