跳到正文

面向开发者

API

API 做两件事:对账户里的站点发起扫描;读取你的账户在应用里能读到的内容——站点、扫描状态与报告。它属于 Gold 与 Platinum 套餐。

认证

  • 在应用的“设置 → API”里创建 key。它只显示一次;我们保存的是它的指纹,不是 key 本身。
  • 每个请求都以 Bearer 令牌的形式带上它。Cookie 会被忽略。
  • 一把 key 有一个或两个权限范围:reports:read(站点、扫描状态、报告)与 scans:create(发起扫描)。
  • key 不等于登录。它不能更改你的账户、站点、账单或 key 本身。如果泄露,撤销它即可,其他 key 不受影响。

所有路径都在 https://app.geoready.org/api 之下。机器可读的接口描述在 https://app.geoready.org/api/v1/openapi.json。

接口

请求Scope作用
GET /v1/me—你的套餐、本周额度,以及发起请求的这把 key。
GET /v1/sitesreports:read账户里的站点。
POST /v1/scansscans:create对其中一个站点发起扫描。
GET /v1/scans/{jobId}reports:read你的账户发起的某次扫描的状态。
GET /v1/reportsreports:read每个站点最近完成的扫描——每站最多 8 条,不是完整历史。
GET /v1/reports/{jobId}reports:read一份报告,内容与详细程度和你在应用里看到的相同。加上 ?locale=zh 返回中文。

GET /v1/me

curl https://app.geoready.org/api/v1/me -H "Authorization: Bearer geoready_…"

# 200
{
  "plan": "gold",
  "quota": { "limit": 260, "remaining": 259, "windowStart": "2026-10-08T00:00:00.000Z" },
  "key": { "name": "Nightly report job", "scopes": ["reports:read", "scans:create"] }
}

GET /v1/sites

curl https://app.geoready.org/api/v1/sites -H "Authorization: Bearer geoready_…"

# 200
{ "sites": [ { "siteKey": "example.com", "role": "OWNED" }, { "siteKey": "example.org", "role": "COMPETITOR" } ] }

POST /v1/scans

curl -X POST https://app.geoready.org/api/v1/scans \
  -H "Authorization: Bearer geoready_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: nightly-2026-10-13" \
  -d '{"domain": "example.com"}'

# 202 — a new scan; 200 with "replayed": true when this Idempotency-Key was used before
{
  "jobId": "0199d2c4-7c1e-7a55-9c7d-3f0f1c2b4a10",
  "siteKey": "example.com",
  "replayed": false,
  "quota": { "limit": 260, "remaining": 259, "windowStart": "2026-10-08T00:00:00.000Z" }
}

GET /v1/scans/{jobId}

curl https://app.geoready.org/api/v1/scans/0199d2c4-7c1e-7a55-9c7d-3f0f1c2b4a10 -H "Authorization: Bearer geoready_…"

# 200 — status is PENDING, RUNNING, SUCCEEDED, INCOMPLETE or FAILED
{
  "jobId": "0199d2c4-7c1e-7a55-9c7d-3f0f1c2b4a10",
  "siteKey": "example.com",
  "status": "SUCCEEDED",
  "createdAt": "2026-10-13T02:00:00.000Z",
  "finishedAt": "2026-10-13T02:00:41.000Z"
}

GET /v1/reports

curl https://app.geoready.org/api/v1/reports -H "Authorization: Bearer geoready_…"

# 200 — baseScore is null when a scan produced no score
{
  "sites": [
    {
      "siteKey": "example.com",
      "role": "OWNED",
      "reports": [
        { "jobId": "0199d2c4-…", "status": "SUCCEEDED", "checkedAt": "2026-10-13T02:00:41.000Z", "baseScore": 72, "pagesLimit": 10 }
      ]
    }
  ]
}

GET /v1/reports/{jobId}

curl "https://app.geoready.org/api/v1/reports/0199d2c4-7c1e-7a55-9c7d-3f0f1c2b4a10?locale=en" -H "Authorization: Bearer geoready_…"

# 200 — abridged: every check row has id, displayClass, goal, outcome, evidence, fix, prompt
{
  "reportId": "0199d2c4-…",
  "siteKey": "example.com",
  "checkedAt": "2026-10-13T02:00:41.000Z",
  "complete": true,
  "baseScore": 72,
  "coverage": 1,
  "fullAccess": true,
  "baseModules": [ { "id": "F08", "displayClass": "scored-fail", "verdict": "fail", "kind": "scoring", "goal": "…", "outcome": "…", "evidence": [], "fix": "…", "prompt": "…" } ],
  "agentModules": [ … ],
  "extraModules": [ … ],
  "paid": { "paidScore": 90, "pagesSampled": 10, "modules": [ … ] },
  "ai": []
}

# 409 while the scan has no finished report
{ "code": "report-not-ready", "message": "…", "details": { "status": "RUNNING" } }

发起扫描

  • 站点必须已经在账户的站点列表里。API 不会替你添加站点。
  • 每次扫描消耗一次每周额度——与应用共用同一个额度。没有单独的 API 额度,API 也不能发起免费检测。
  • 应答里有扫描的 id 和你当前的额度。轮询状态接口,直到状态为 SUCCEEDED、INCOMPLETE 或 FAILED,然后读取报告。

安全地重试

  • 带上 Idempotency-Key 请求头(8–128 个可打印 ASCII 字符),请求就可以安全地重试。
  • 用相同的键、相同的域名再次请求,会返回第一次的扫描,"replayed": true,状态码 200,不扣额度——即使此后额度已用完、站点已从列表移除,或那次扫描失败了。想重新扫描,请换一个新的键。
  • 同一个键配不同的域名会被拒绝(409)。
  • 键属于发送它的那把 API key:两把 key 可以各自使用相同的值,互不影响。
  • 没有固定的有效期:只要那次扫描还在,键就一直被记住。
  • 套餐结束后,重放与其他请求一样被拒绝(403)。

错误

所有错误的结构相同:一个稳定的代码、一句给人看的说明,有时带有详情。

{ "code": "quota-exhausted", "message": "…", "details": { "quota": { "limit": 260, "remaining": 0, "windowStart": "…" } } }
状态码代码何时出现
400invalid-request请求体、参数或 Idempotency-Key 请求头格式不对。
400invalid-domain无法识别这个域名。
401unauthorized没有 key,或 key 不存在、已撤销、已过期。这几种情况的应答完全相同。
403api-not-in-plan你的套餐不包含 API(或已结束)。
403insufficient-scope这把 key 没有此请求需要的权限范围。
403quota-exhausted本周额度已用完。
404not-found路径、扫描或报告不存在——或者你无权读取。
404site-not-tracked这个域名不在你账户的站点列表里。
409idempotency-conflict这个 Idempotency-Key 已经用于另一个域名。
409report-not-ready这次扫描还没有成品报告;details.status 给出当前状态。
429rate-limited请求过多。Retry-After 给出何时可以重试。
500internal-error我们这边出了问题。

Webhook

本服务尚未开启 Webhook。目前请轮询扫描状态接口。

限流

  • 每把 key 每分钟 60 次,每个账户每分钟 120 次,每个地址每分钟 300 次。
  • 每把 key 每分钟最多发起 10 次扫描。
  • 每个地址每分钟最多 30 次缺少 key 或 key 错误的请求。
  • 超出限制会得到 429,并带有 Retry-After 请求头。

API 不做的事

  • 免费检测,以及对不在你列表里的站点的扫描。
  • 添加或删除站点、账单、账户设置、key 管理。
  • 发起 AI 分析,或更改报告是否分享。