{"openapi":"3.1.0","info":{"title":"PerfBee API","description":"The PerfBee REST API. Everything the dashboard shows about a crawl is here as JSON, and a crawl can be started and watched.\n\n**Authentication.** Send a workspace API key as `Authorization: Bearer pbk_...`. Keys are made in Settings > API keys and\ncarry scopes: `read`, `crawl` (includes read) and `webhooks`. Nothing else is accepted: not a key in the URL, not a cookie,\nnot a dashboard token.\n\n**Errors** are RFC 9457 `application/problem+json` with a stable `code` (see `ProblemDetail`). A shortage of credits is\n**402**, never 429.\n\n**Lists** answer `{\"data\": [...], \"next_cursor\": \"...\" | null, \"has_more\": bool}`; pass `next_cursor` back as `cursor`.\nCursors are opaque. Clients must ignore fields and enum values they do not know: within v1 only additions happen.\n\n**Rate limits** are per key and per workspace, per minute; every answer carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`\nand `X-RateLimit-Reset`, and a 429 carries `Retry-After`.\n","contact":{"name":"PerfBee support","url":"https://perfbee.com/developers","email":"support@perfbee.com"},"version":"1.0.0"},"servers":[{"url":"https://dashboard.perfbee.com/api/v1","description":"Production"}],"paths":{"/me":{"get":{"tags":["Account"],"summary":"Show the key, its workspace, plan and credits","description":"Returns what the API key you send acts as: the workspace and your role in it, the plan and the flags that matter to API users (exports, team seats), this month's credits and what a page costs, the key's own scopes, daily credit cap and expiry (never its secret), and which parts of the API are switched on. Call it first to check a key and a budget. It is free, and needs the `read` scope.","operationId":"get_me","responses":{"200":{"description":"OK. The body is a `Me`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/sites":{"get":{"tags":["Crawls"],"summary":"List your sites","description":"Your workspace's sites (My Sites in the dashboard), by id, each with its newest crawl, its next scheduled crawl, whether you verified the host, its crawl profile and whether the fast lane is on. Paged with `cursor`. Secrets of the site (crawl token, RUM token) are never part of the answer. Free; needs `read`.","operationId":"list_sites","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `SiteList`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteList"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/sites/{site_id}":{"get":{"tags":["Crawls"],"summary":"Get one site","description":"One of your sites with its newest crawl, schedule, verification, crawl profile and fast-lane flag. A site of another workspace, a removed site and an unknown id are all 404. Free; needs `read`.","operationId":"get_site","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer","maximum":2147483647,"minimum":1,"description":"The site's id (from GET /sites).","title":"Site Id"},"description":"The site's id (from GET /sites)."}],"responses":{"200":{"description":"OK. The body is a `Site`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/crawls":{"get":{"tags":["Crawls"],"summary":"List crawls","description":"Your crawls, newest first. These are the crawls you started, scheduled or that started a new site (the dashboard's Scans list); the product's own \"Check if fixed\" runs are not crawls. Filter by `site_id` (the dashboard's per-site list: a root site also lists its sub-folder crawls), `status`, `mode` and `since` (crawls queued at or after this time, ISO 8601, UTC when it has no zone; write the zone as `Z` or `%2B02:00`). Paged with `cursor`. Each crawl carries its live `progress` and `processing`, so one call is enough to follow several crawls. Free; needs `read`.","operationId":"list_crawls","parameters":[{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":2147483647,"minimum":1},{"type":"null"}],"description":"Only crawls of this site (an id from GET /sites).","title":"Site Id"},"description":"Only crawls of this site (an id from GET /sites)."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"enum":["pending","running","completed","failed","cancelled","partial"],"type":"string"},{"type":"null"}],"description":"Only crawls in this status.","title":"Status"},"description":"Only crawls in this status."},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"enum":["fast","full"],"type":"string"},{"type":"null"}],"description":"Only fast or only full (detailed) crawls.","title":"Mode"},"description":"Only fast or only full (detailed) crawls."},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"Only crawls queued at or after this time (ISO 8601; UTC if no zone).","title":"Since"},"description":"Only crawls queued at or after this time (ISO 8601; UTC if no zone)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `CrawlPage`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlPage"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"},"post":{"tags":["Crawl control"],"summary":"Start a crawl","description":"Starts a crawl of one of your sites (My Sites) and returns at once with `202 Accepted`, the crawl object and a `Location` header; follow it with `GET /crawls/{id}`. It goes through the same checks as the dashboard (public addresses only, blocked domains, your plan's rates, the owned-site rate for a verified site).\n\n**Credits.** Credits are checked before the crawl exists: the most it can cost (`max_pages` times the page rate) must fit what the workspace has left this month, less what your other running API crawls may still spend (402 `insufficient_credits` otherwise; `credits.available` is already net of those holds). You are charged when the crawl ends, for the pages it checked.\n\n**Limits.** A key's `daily_credit_cap` bounds the worst-case cost of the crawls it starts per UTC day (429 `daily_credit_cap_reached`); a key made without one may crawl at most 500 pages. Crawls of one site through the API must be 10 minutes apart (429 `crawl_too_soon`; a crawl cancelled before it started does not count). A key may start 10 crawls a day and the workspace 20; 2 may run at once. A site that already has a pending or running crawl answers 409 `crawl_in_progress` with that crawl's id.\n\n**Idempotency.** Send `Idempotency-Key` (1 to 255 characters) to make a retry safe: the same key with the same body returns the crawl the first request started (`200` and `Idempotent-Replayed: true`); the same key with another body is 422 `idempotency_key_reused`; a request still being made answers 409 `idempotency_in_progress`. Keys are remembered for 24 hours. Use something unique per intended crawl, for example a commit hash.\n\nNeeds the `crawl` scope. Until starting crawls through the API is switched on, this route answers 404.","operationId":"start_crawl","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string","minLength":1,"maxLength":255},{"type":"null"}],"description":"Makes a retry of this request safe: the same key and body return the crawl already started.","title":"Idempotency-Key"},"description":"Makes a retry of this request safe: the same key and body return the crawl already started."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartCrawlRequest"}}}},"responses":{"200":{"description":"A retry of a start the Idempotency-Key had already made: the same crawl, nothing new was started.","headers":{"Idempotent-Replayed":{"description":"Always `true` on this answer.","schema":{"type":"string"}},"Location":{"description":"The crawl's URL.","schema":{"type":"string"}},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlStarted"}}}},"202":{"description":"The crawl was queued. `Location` is its URL; `Retry-After` is when to look at it first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlStarted"}}},"headers":{"Location":{"description":"The crawl's URL: GET it for its progress.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before the first look.","schema":{"type":"integer"}},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"402":{"description":"Not enough credits: The operation needs more credits than the workspace has left this month. `credits` says how many are needed and free.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"insufficient_credits":{"summary":"Not enough credits","value":{"type":"https://perfbee.com/developers/errors#insufficient_credits","title":"Not enough credits","status":402,"code":"insufficient_credits","detail":"The operation needs more credits than the workspace has left this month. `credits` says how many are needed and free.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Request in progress: A request with the same Idempotency-Key is still being handled; retry shortly.; Crawl in progress: A crawl of this site is already pending or running; `crawl_id` in the problem is that crawl.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"idempotency_in_progress":{"summary":"Request in progress","value":{"type":"https://perfbee.com/developers/errors#idempotency_in_progress","title":"Request in progress","status":409,"code":"idempotency_in_progress","detail":"A request with the same Idempotency-Key is still being handled; retry shortly.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"crawl_in_progress":{"summary":"Crawl in progress","value":{"type":"https://perfbee.com/developers/errors#crawl_in_progress","title":"Crawl in progress","status":409,"code":"crawl_in_progress","detail":"A crawl of this site is already pending or running; `crawl_id` in the problem is that crawl.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Idempotency key reused: The Idempotency-Key was already used with a different request body.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"idempotency_key_reused":{"summary":"Idempotency key reused","value":{"type":"https://perfbee.com/developers/errors#idempotency_key_reused","title":"Idempotency key reused","status":422,"code":"idempotency_key_reused","detail":"The Idempotency-Key was already used with a different request body.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Daily credit cap reached: The crawls this key started today, counted at their worst case, plus this one would pass the key's daily credit cap. `daily_credit_cap` says the cap, what was used and what this crawl needs; `Retry-After` is the time to the next UTC day.; Crawl too soon: The site was crawled through the API less than 10 minutes ago (by REST or the MCP server). Crawls of one site through the API must be that far apart; `Retry-After` is the time left.; Daily crawl limit reached: The key started 10 crawls today (UTC), or the workspace 20. `crawl_limit` says which; `Retry-After` is the time to the next UTC day.; Too many running crawls: The workspace already has 2 API crawls running. Wait for one to end, or cancel one.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"daily_credit_cap_reached":{"summary":"Daily credit cap reached","value":{"type":"https://perfbee.com/developers/errors#daily_credit_cap_reached","title":"Daily credit cap reached","status":429,"code":"daily_credit_cap_reached","detail":"The crawls this key started today, counted at their worst case, plus this one would pass the key's daily credit cap. `daily_credit_cap` says the cap, what was used and what this crawl needs; `Retry-After` is the time to the next UTC day.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"crawl_too_soon":{"summary":"Crawl too soon","value":{"type":"https://perfbee.com/developers/errors#crawl_too_soon","title":"Crawl too soon","status":429,"code":"crawl_too_soon","detail":"The site was crawled through the API less than 10 minutes ago (by REST or the MCP server). Crawls of one site through the API must be that far apart; `Retry-After` is the time left.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"crawl_limit_reached":{"summary":"Daily crawl limit reached","value":{"type":"https://perfbee.com/developers/errors#crawl_limit_reached","title":"Daily crawl limit reached","status":429,"code":"crawl_limit_reached","detail":"The key started 10 crawls today (UTC), or the workspace 20. `crawl_limit` says which; `Retry-After` is the time to the next UTC day.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_running_crawls":{"summary":"Too many running crawls","value":{"type":"https://perfbee.com/developers/errors#too_many_running_crawls","title":"Too many running crawls","status":429,"code":"too_many_running_crawls","detail":"The workspace already has 2 API crawls running. Wait for one to end, or cancel one.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Service busy: The service has no free capacity for this request right now; retry after `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"crawl","x-rate-class":"start"}},"/crawls/{crawl_id}":{"get":{"tags":["Crawls"],"summary":"Get one crawl","description":"One crawl: status, counts, what it covered, credits charged, live `progress` while it runs and `processing`, which says whether the crawl's pages and fixes are ready yet (a crawl is `completed` before they are). Add `wait` (1 to 25 seconds) to hold the call while the crawl is pending or running: it returns as soon as the crawl is over, or after `wait` seconds with the current state; repeat until `status` is final. A wait holds one server thread but no database connection; when this server has too many waits open it answers at once with `Retry-After` instead of waiting. A crawl of another workspace is 404. Free; needs `read`.","operationId":"get_crawl","parameters":[{"name":"crawl_id","in":"path","required":true,"schema":{"type":"string","title":"Crawl Id"},"description":"The crawl's id (a UUID): from `GET /crawls` or the answer of `POST /crawls`."},{"name":"wait","in":"query","required":false,"schema":{"type":"integer","maximum":25,"minimum":0,"description":"Seconds to wait for a pending or running crawl to end, 0 to 25.","default":0,"title":"Wait"},"description":"Seconds to wait for a pending or running crawl to end, 0 to 25."}],"responses":{"200":{"description":"The crawl. `Retry-After` is set when a `wait` was asked for but this server has too many waits open: the answer is the current state, poll again after that many seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Crawl"}}},"headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/crawls/{crawl_id}/links":{"get":{"tags":["Crawls"],"summary":"List the URLs a crawl checked","description":"Every URL the crawl checked (pages, links, images, scripts...), in crawl order, paged with `cursor`: the status, whether it is broken, why it was not checked, its type, depth, how many pages link to it and where a redirect leads. Filters: `is_broken`, `resource_type`, `status` (the word) and `status_code`. `include=count` adds `total` (one extra count). v1 lists no source pages per link. A crawl that is still pending or running answers 409 `crawl_not_ready`. Free; needs `read`; counts as a heavy call.","operationId":"list_crawl_links","parameters":[{"name":"crawl_id","in":"path","required":true,"schema":{"type":"string","title":"Crawl Id"},"description":"The crawl's id (a UUID): from `GET /crawls` or the answer of `POST /crawls`."},{"name":"is_broken","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"True: only broken URLs. False: everything else.","title":"Is Broken"},"description":"True: only broken URLs. False: everything else."},{"name":"resource_type","in":"query","required":false,"schema":{"anyOf":[{"enum":["link","image","css","js","video","iframe","audio","embed","object"],"type":"string"},{"type":"null"}],"description":"Only this kind of URL.","title":"Resource Type"},"description":"Only this kind of URL."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"enum":["working","redirect","broken","not_checked"],"type":"string"},{"type":"null"}],"description":"Only this status word.","title":"Status"},"description":"Only this status word."},{"name":"status_code","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":599,"minimum":100},{"type":"null"}],"description":"Only this HTTP status code.","title":"Status Code"},"description":"Only this HTTP status code."},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"const":"count"},{"type":"null"}],"description":"`count` adds `total`: how many URLs match.","title":"Include"},"description":"`count` adds `total`: how many URLs match."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `LinkPage`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkPage"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Crawl not ready: The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"crawl_not_ready":{"summary":"Crawl not ready","value":{"type":"https://perfbee.com/developers/errors#crawl_not_ready","title":"Crawl not ready","status":409,"code":"crawl_not_ready","detail":"The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Query too slow: The data query ran past its time limit; narrow the filters or the page size and try again.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"query_too_slow":{"summary":"Query too slow","value":{"type":"https://perfbee.com/developers/errors#query_too_slow","title":"Query too slow","status":503,"code":"query_too_slow","detail":"The data query ran past its time limit; narrow the filters or the page size and try again.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"read","x-rate-class":"heavy"}},"/crawls/{crawl_id}/ai-readiness":{"get":{"tags":["Crawls"],"summary":"Get a crawl's AI readiness report","description":"The AI Search Readiness report of a detailed crawl, as the dashboard shows it: which AI bots can reach the site (from robots.txt), the site-level checks, and exact page counts per issue. A fast crawl and a crawl that never got the report are 404 `ai_readiness_unavailable` (`reason`: `fast_mode` or `missing`); a crawl that is running, or whose report is still being written, is 409 `crawl_not_ready`. Free; needs `read`; counts as a heavy call (the page counts are worked out from the crawl's pages on every call).","operationId":"get_crawl_ai_readiness","parameters":[{"name":"crawl_id","in":"path","required":true,"schema":{"type":"string","title":"Crawl Id"},"description":"The crawl's id (a UUID): from `GET /crawls` or the answer of `POST /crawls`."}],"responses":{"200":{"description":"OK. The body is a `AiReadiness`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiReadiness"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).; No AI readiness report: The crawl has no AI readiness report: a fast crawl extracts no page data, and a detailed crawl that stopped early or is older than the report has none. `reason` says which.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"ai_readiness_unavailable":{"summary":"No AI readiness report","value":{"type":"https://perfbee.com/developers/errors#ai_readiness_unavailable","title":"No AI readiness report","status":404,"code":"ai_readiness_unavailable","detail":"The crawl has no AI readiness report: a fast crawl extracts no page data, and a detailed crawl that stopped early or is older than the report has none. `reason` says which.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Crawl not ready: The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"crawl_not_ready":{"summary":"Crawl not ready","value":{"type":"https://perfbee.com/developers/errors#crawl_not_ready","title":"Crawl not ready","status":409,"code":"crawl_not_ready","detail":"The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Query too slow: The data query ran past its time limit; narrow the filters or the page size and try again.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"query_too_slow":{"summary":"Query too slow","value":{"type":"https://perfbee.com/developers/errors#query_too_slow","title":"Query too slow","status":503,"code":"query_too_slow","detail":"The data query ran past its time limit; narrow the filters or the page size and try again.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"read","x-rate-class":"heavy"}},"/crawls/{crawl_id}/exports/{slug}.{file_format}":{"get":{"tags":["Crawls"],"summary":"Download a crawl's report as CSV or Excel","description":"The dashboard's export of one crawl, byte for byte the same code: `slug` is the report (`broken-links`, `all-urls`, `seo`, `ai-suggestions`, `duplicates`, `css-js`, `images`, `extraction`, `custom-search`, `orphans`, `redirect-chains`, `canonical-chains`, `elements`, and `links` and `anchor-text` while the link graph is on), the format is `csv` or `xlsx`. Needs a plan with exports (Starter and up), and for `ai-suggestions` and `elements` the plan features the dashboard asks for. The whole report is served: no row selection and no filter. A report with more rows than a request may build (250,000 for CSV, 150,000 for Excel) is refused with 413 `export_too_large`, never cut; a crawl that is still running, or a report this crawl cannot make (`links` needs link capture), is 409 `crawl_not_ready`. Counts as a heavy call.","operationId":"export_crawl","parameters":[{"name":"crawl_id","in":"path","required":true,"schema":{"type":"string","title":"Crawl Id"},"description":"The crawl's id (a UUID): from `GET /crawls` or the answer of `POST /crawls`."},{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"},"description":"The report to download, for example `broken-links`: the operation description lists them."},{"name":"file_format","in":"path","required":true,"schema":{"enum":["csv","xlsx"],"type":"string","title":"File Format"},"description":"`csv` or `xlsx`."}],"responses":{"200":{"description":"The file, built by the dashboard's own export code: same columns, same file name (`Content-Disposition`), same content as the dashboard's download.","content":{"text/csv":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"schema":{"type":"string","format":"binary"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Plan upgrade required: The workspace's plan does not include this feature.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"plan_required":{"summary":"Plan upgrade required","value":{"type":"https://perfbee.com/developers/errors#plan_required","title":"Plan upgrade required","status":403,"code":"plan_required","detail":"The workspace's plan does not include this feature.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Crawl not ready: The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"crawl_not_ready":{"summary":"Crawl not ready","value":{"type":"https://perfbee.com/developers/errors#crawl_not_ready","title":"Crawl not ready","status":409,"code":"crawl_not_ready","detail":"The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"413":{"description":"Export too large: The export holds more rows than a direct download allows; narrow it or use the dashboard's export job.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"export_too_large":{"summary":"Export too large","value":{"type":"https://perfbee.com/developers/errors#export_too_large","title":"Export too large","status":413,"code":"export_too_large","detail":"The export holds more rows than a direct download allows; narrow it or use the dashboard's export job.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Query too slow: The data query ran past its time limit; narrow the filters or the page size and try again.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"query_too_slow":{"summary":"Query too slow","value":{"type":"https://perfbee.com/developers/errors#query_too_slow","title":"Query too slow","status":503,"code":"query_too_slow","detail":"The data query ran past its time limit; narrow the filters or the page size and try again.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"read","x-rate-class":"heavy"}},"/crawls/{crawl_id}/issues":{"get":{"tags":["Issues"],"summary":"List a crawl's issues","description":"The issues of a completed crawl, most important first: broken links and resources (with the page and the HTML element they sit in, most linked first), page SEO issues, then AI readiness issues, each with a short fix. Filter by `category`, `severity` and `code`. Pages the site refused are counted as not checked, never as broken. A fast crawl has broken links only: asking for `seo` or `ai_readiness` answers an empty list.\n\nLists are cursor pages (`next_cursor` back as `cursor`, up to 100 per page). A page can hold fewer issues than `limit` while `has_more` is true: a filter that matches few issues is searched in bounded steps, so keep following the cursor until `has_more` is false. The first page also carries the crawl's `totals`, counted once when the crawl was processed (null with `totals_status: pending` until then).","operationId":"list_crawl_issues","parameters":[{"name":"crawl_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"description":"The crawl's id (a UUID).","title":"Crawl Id"},"description":"The crawl's id (a UUID)."},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"enum":["broken","seo","ai_readiness"],"type":"string"},{"type":"null"}],"description":"Only this category. Default: all of them.","title":"Category"},"description":"Only this category. Default: all of them."},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"enum":["error","warning","info"],"type":"string"},{"type":"null"}],"description":"Only issues of this severity.","title":"Severity"},"description":"Only issues of this severity."},{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"description":"Only this issue code, for example `missing_title`.","title":"Code"},"description":"Only this issue code, for example `missing_title`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Items per page, 1 to 100.","default":50,"title":"Limit"},"description":"Items per page, 1 to 100."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `IssuePage`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssuePage"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Crawl not ready: The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"crawl_not_ready":{"summary":"Crawl not ready","value":{"type":"https://perfbee.com/developers/errors#crawl_not_ready","title":"Crawl not ready","status":409,"code":"crawl_not_ready","detail":"The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Query too slow: The data query ran past its time limit; narrow the filters or the page size and try again.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"query_too_slow":{"summary":"Query too slow","value":{"type":"https://perfbee.com/developers/errors#query_too_slow","title":"Query too slow","status":503,"code":"query_too_slow","detail":"The data query ran past its time limit; narrow the filters or the page size and try again.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"read","x-rate-class":"heavy"}},"/crawls/{crawl_id}/diff":{"get":{"tags":["Issues"],"summary":"Compare a crawl with the previous one","description":"What changed between a completed crawl and the previous completed crawl of the same site in the same mode (or any other completed crawl of the site in the same mode: `against`). Counts of new, disappeared and changed pages and of new, fixed and persistent broken links. Only what this crawl saw counts as a change: a link is `fixed` when it was checked again and works, a page `disappeared` when it now answers an error or redirect or the crawl covered the whole site; `not_rechecked` and `not_reached` count the rest.\n\nThe summary of the previous-crawl comparison is counted once when the crawl is processed and served from there (`source: stored`). Pass `include=lists` for the first `limit` pages and links of each kind (it is counted for the request). Crawls of more than 100,000 pages are compared by their broken links alone (`pages_compared: false`; a comparison counted for a request does so above 25,000 pages). A crawl with no earlier crawl answers `has_previous: false`, not an error. A CI gate: `curl .../crawls/$ID/diff | jq -e '.summary.new_broken == 0'`.","operationId":"get_crawl_diff","parameters":[{"name":"crawl_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"description":"The crawl's id (a UUID).","title":"Crawl Id"},"description":"The crawl's id (a UUID)."},{"name":"against","in":"query","required":false,"schema":{"type":"string","maxLength":64,"description":"`previous` (default), or the id of another completed crawl of the same site and mode.","default":"previous","title":"Against"},"description":"`previous` (default), or the id of another completed crawl of the same site and mode."},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"const":"lists"},{"type":"null"}],"description":"`lists`: also the first `limit` items of each list.","title":"Include"},"description":"`lists`: also the first `limit` items of each list."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per list with `include=lists`.","default":50,"title":"Limit"},"description":"Items per list with `include=lists`."}],"responses":{"200":{"description":"OK. The body is a `CrawlDiff`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlDiff"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Crawl not ready: The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"crawl_not_ready":{"summary":"Crawl not ready","value":{"type":"https://perfbee.com/developers/errors#crawl_not_ready","title":"Crawl not ready","status":409,"code":"crawl_not_ready","detail":"The crawl's data is not available yet or any more; retry after the time in `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Query too slow: The data query ran past its time limit; narrow the filters or the page size and try again.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"query_too_slow":{"summary":"Query too slow","value":{"type":"https://perfbee.com/developers/errors#query_too_slow","title":"Query too slow","status":503,"code":"query_too_slow","detail":"The data query ran past its time limit; narrow the filters or the page size and try again.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"read","x-rate-class":"heavy"}},"/sites/{site_id}/pages":{"get":{"tags":["Pages"],"summary":"List a site's pages","description":"The site's page inventory, the list behind Site Pages in the dashboard: one row per URL the crawls found, with its status, its SEO data (from the newest detailed crawl) and the issue codes it carries. Choose a `view` and narrow it with the filters of the dashboard. The order is always by URL, and the list is a keyset: pass `next_cursor` back as `cursor`. `inventory` says which crawl the list shows and whether it covered the whole site. A filter that matches few rows can take long; past 15 seconds the answer is 503 `query_too_slow`, so narrow it with `prefix` or a `view`. `include=count` adds the counts behind the dashboard's chips (one more, heavier query). For other sort orders download an export. Needs the `read` scope; free of credits.","operationId":"list_site_pages","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The site's id (`GET /sites`).","title":"Site Id"},"description":"The site's id (`GET /sites`)."},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"const":"count"},{"type":"null"}],"description":"`count` adds `counts`.","title":"Include"},"description":"`count` adds `counts`."},{"name":"view","in":"query","required":false,"schema":{"enum":["pages","resources","links_out","missing"],"type":"string","description":"pages: HTML pages. resources: images, scripts, styles, fonts, media and the site's own files. links_out: pages and files outside the site or its folder that the site links to. missing: URLs a later complete crawl no longer found.","default":"pages","title":"View"},"description":"pages: HTML pages. resources: images, scripts, styles, fonts, media and the site's own files. links_out: pages and files outside the site or its folder that the site links to. missing: URLs a later complete crawl no longer found."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"enum":["ok","redirect","broken","gone","not_checked","unknown"],"type":"string"},{"type":"null"}],"description":"Only URLs with this status class.","title":"Status"},"description":"Only URLs with this status class."},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"enum":["page","document","other","image","css","js","font","video","iframe","audio","embed"],"type":"string"},{"type":"null"}],"description":"Only URLs of this type.","title":"Type"},"description":"Only URLs of this type."},{"name":"indexability","in":"query","required":false,"schema":{"anyOf":[{"enum":["indexable","non_indexable","unknown"],"type":"string"},{"type":"null"}],"description":"Only pages with this indexability.","title":"Indexability"},"description":"Only pages with this indexability."},{"name":"issue","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"description":"Only URLs carrying this issue code (`GET /issue-types`).","title":"Issue"},"description":"Only URLs carrying this issue code (`GET /issue-types`)."},{"name":"change","in":"query","required":false,"schema":{"anyOf":[{"enum":["new","changed"],"type":"string"},{"type":"null"}],"description":"Only URLs new or changed in the newest crawl.","title":"Change"},"description":"Only URLs new or changed in the newest crawl."},{"name":"resolved","in":"query","required":false,"schema":{"enum":["show","hide","only"],"type":"string","description":"show, hide or list only the URLs someone marked resolved.","default":"show","title":"Resolved"},"description":"show, hide or list only the URLs someone marked resolved."},{"name":"prefix","in":"query","required":false,"schema":{"type":"string","maxLength":2000,"description":"Only URLs that start with this text.","default":"","title":"Prefix"},"description":"Only URLs that start with this text."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Only URLs that contain this text.","default":"","title":"Q"},"description":"Only URLs that contain this text."},{"name":"sort","in":"query","required":false,"schema":{"const":"url","description":"URL order is the only one the list offers: for other orders download an export.","default":"url","title":"Sort"},"description":"URL order is the only one the list offers: for other orders download an export."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `SitePageList`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitePageList"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Query too slow: The data query ran past its time limit; narrow the filters or the page size and try again.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"query_too_slow":{"summary":"Query too slow","value":{"type":"https://perfbee.com/developers/errors#query_too_slow","title":"Query too slow","status":503,"code":"query_too_slow","detail":"The data query ran past its time limit; narrow the filters or the page size and try again.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"read","x-rate-class":"heavy"}},"/sites/{site_id}/pages/{page_id}":{"get":{"tags":["Pages"],"summary":"Get one page of a site","description":"One row of the site's inventory with the issues on it in words (labels from `GET /issue-types`) and the pages that link to it in the newest crawl that saw it. The crawl stores at most 200 linking pages per URL and this answer lists the first 50 by URL; `linking_pages` says the cap, how many are listed and how many pages link here in all. Needs the `read` scope; free of credits.","operationId":"get_site_page","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The site's id (`GET /sites`).","title":"Site Id"},"description":"The site's id (`GET /sites`)."},{"name":"page_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The page's id (`GET /sites/{site_id}/pages`).","title":"Page Id"},"description":"The page's id (`GET /sites/{site_id}/pages`)."}],"responses":{"200":{"description":"OK. The body is a `SitePageDetail`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitePageDetail"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/issue-types":{"get":{"tags":["Pages"],"summary":"List the issue catalog","description":"Every issue code a page can carry (`issues` of a page, the `issue` filter, fixes) with its label, severity, category, what it looks at, why it matters and how to fix it. The catalog grows: codes are never renumbered or reused, so ignore codes you do not know. It is one page: no limit or cursor. Needs the `read` scope; free of credits.","operationId":"list_issue_types","responses":{"200":{"description":"OK. A page of `IssueType` objects, with `next_cursor` and `has_more`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPage_IssueType_"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/webhook-events":{"get":{"tags":["Pages"],"summary":"List the webhook events","description":"Every event a webhook endpoint can subscribe to, with the part of the product it belongs to and when it fires. It is one page: no limit or cursor. Needs the `read` scope; free of credits.","operationId":"list_webhook_events","responses":{"200":{"description":"OK. A page of `WebhookEventType` objects, with `next_cursor` and `has_more`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPage_WebhookEventType_"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/sites/{site_id}/fixes":{"get":{"tags":["Pages"],"summary":"List a site's fixes","description":"The site's fix list, the Fixes view of the dashboard: each issue grouped by page template (one change fixes every page built from it), the whole site or separate pages, and every broken link, best score first. `status` picks open fixes (the default), those the team set aside, resolved ones or all. The score and rank only order the list: the weights are still being tuned. It is a keyset: pass `next_cursor` back as `cursor`. `include=count` adds the counts per status and severity. The view is behind a switch in the dashboard and these routes are 404 wherever it is hidden. Needs the `read` scope; free of credits.","operationId":"list_site_fixes","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The site's id (`GET /sites`).","title":"Site Id"},"description":"The site's id (`GET /sites`)."},{"name":"status","in":"query","required":false,"schema":{"enum":["open","set_aside","resolved","all"],"type":"string","description":"open, set_aside (accepted, won't fix or snoozed), resolved or all.","default":"open","title":"Status"},"description":"open, set_aside (accepted, won't fix or snoozed), resolved or all."},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"enum":["error","warning","info"],"type":"string"}},{"type":"null"}],"description":"Only these severities; repeat the parameter.","title":"Severity"},"description":"Only these severities; repeat the parameter."},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"enum":["site","template","pages","link"],"type":"string"},{"type":"null"}],"description":"Only fixes of this kind.","title":"Kind"},"description":"Only fixes of this kind."},{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"description":"Only fixes of this issue code.","title":"Code"},"description":"Only fixes of this issue code."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Only fixes whose issue, template or URL contains this.","default":"","title":"Q"},"description":"Only fixes whose issue, template or URL contains this."},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"const":"count"},{"type":"null"}],"description":"`count` adds `counts`.","title":"Include"},"description":"`count` adds `counts`."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `FixList`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixList"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/sites/{site_id}/fixes/{fix_id}":{"get":{"tags":["Pages"],"summary":"Get one fix","description":"One fix with the issue in words (what is wrong, why it matters, how to fix it, naming an example page) and its history, the latest 50 events newest first. People behind decisions are not named. Needs the `read` scope; free of credits.","operationId":"get_site_fix","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The site's id (`GET /sites`).","title":"Site Id"},"description":"The site's id (`GET /sites`)."},{"name":"fix_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The fix's id (`GET /sites/{site_id}/fixes`).","title":"Fix Id"},"description":"The fix's id (`GET /sites/{site_id}/fixes`)."}],"responses":{"200":{"description":"OK. The body is a `FixDetail`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixDetail"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/sites/{site_id}/fixes/{fix_id}/pages":{"get":{"tags":["Pages"],"summary":"List the pages of a fix","description":"The pages a fix is about. For a fix of pages, templates or the whole site these are the affected pages, most linked first, as a keyset: pass `next_cursor` back as `cursor` (a sort over the whole set, so a very large fix can answer 503 `query_too_slow`: narrow it with `q`). For a link fix they are the pages that link to the broken URL with the anchor text and the HTML element: a crawl stores at most 200 of them, so that list is short and sorted by URL. `kind` says which. `q` keeps URLs containing it. Needs the `read` scope; free of credits.","operationId":"list_site_fix_pages","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The site's id (`GET /sites`).","title":"Site Id"},"description":"The site's id (`GET /sites`)."},{"name":"fix_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The fix's id (`GET /sites/{site_id}/fixes`).","title":"Fix Id"},"description":"The fix's id (`GET /sites/{site_id}/fixes`)."},{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":200,"description":"Only URLs that contain this.","default":"","title":"Q"},"description":"Only URLs that contain this."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `FixPageList`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixPageList"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Query too slow: The data query ran past its time limit; narrow the filters or the page size and try again.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"query_too_slow":{"summary":"Query too slow","value":{"type":"https://perfbee.com/developers/errors#query_too_slow","title":"Query too slow","status":503,"code":"query_too_slow","detail":"The data query ran past its time limit; narrow the filters or the page size and try again.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"read","x-rate-class":"heavy"}},"/feeds":{"post":{"tags":["Pages"],"summary":"Make a live link","description":"Makes a live CSV link for one of the workspace's sites and one table: `crawl-history` (one row per finished crawl), `broken-links`, `all-urls`, `seo` (the newest crawl's tables, followed on every read) or `site-pages` (the Site Pages list with the `filters` you give). Paste `formula` into Google Sheets. **The link is in this answer only**: it is a secret, anyone who has it can read the data, and it is never shown again (revoke it with `DELETE /feeds/{feed_id}`). It stops working after a year. Refused: a site with staging access, a table above the size a live link holds, and a workspace at its limit. Needs the `read` scope and a plan with exports; a viewer's key cannot make one. Free of credits.","operationId":"create_feed","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedCreate"}}}},"responses":{"201":{"description":"Created. The body is a `FeedCreated`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedCreated"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Plan upgrade required: The workspace's plan does not include this feature.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"plan_required":{"summary":"Plan upgrade required","value":{"type":"https://perfbee.com/developers/errors#plan_required","title":"Plan upgrade required","status":403,"code":"plan_required","detail":"The workspace's plan does not include this feature.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Site has staging access: The site has staging access set up, so its data cannot be shared through a live link.; Live link limit reached: The workspace already has as many live links as it may; revoke one first.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"feed_site_has_staging_access":{"summary":"Site has staging access","value":{"type":"https://perfbee.com/developers/errors#feed_site_has_staging_access","title":"Site has staging access","status":409,"code":"feed_site_has_staging_access","detail":"The site has staging access set up, so its data cannot be shared through a live link.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"feed_limit_reached":{"summary":"Live link limit reached","value":{"type":"https://perfbee.com/developers/errors#feed_limit_reached","title":"Live link limit reached","status":409,"code":"feed_limit_reached","detail":"The workspace already has as many live links as it may; revoke one first.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"413":{"description":"Live link too large: The dataset holds more rows or cells than a live link can; narrow it with filters or download an export.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"feed_too_large":{"summary":"Live link too large","value":{"type":"https://perfbee.com/developers/errors#feed_too_large","title":"Live link too large","status":413,"code":"feed_too_large","detail":"The dataset holds more rows or cells than a live link can; narrow it with filters or download an export.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"},"get":{"tags":["Pages"],"summary":"List the live links","description":"The workspace's live links, newest first, revoked and expired ones included (owners and admins see every link, other members the ones they made). A link's address is never listed: it was shown once, when the link was made. Needs the `read` scope and a plan with exports; free of credits.","operationId":"list_feeds","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. The body is a `FeedList`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedList"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Plan upgrade required: The workspace's plan does not include this feature.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"plan_required":{"summary":"Plan upgrade required","value":{"type":"https://perfbee.com/developers/errors#plan_required","title":"Plan upgrade required","status":403,"code":"plan_required","detail":"The workspace's plan does not include this feature.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/feeds/{feed_id}":{"delete":{"tags":["Pages"],"summary":"Revoke a live link","description":"Revokes a live link: the address stops working at once and cannot be brought back (make a new link). Revoking twice answers the same. Returns the feed as it is now. Needs the `read` scope and a plan with exports; free of credits.","operationId":"revoke_feed","parameters":[{"name":"feed_id","in":"path","required":true,"schema":{"type":"integer","maximum":9223372036854775807,"minimum":1,"description":"The live link's id (`GET /feeds`).","title":"Feed Id"},"description":"The live link's id (`GET /feeds`)."}],"responses":{"200":{"description":"OK. The body is a `Feed`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feed"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Plan upgrade required: The workspace's plan does not include this feature.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"plan_required":{"summary":"Plan upgrade required","value":{"type":"https://perfbee.com/developers/errors#plan_required","title":"Plan upgrade required","status":403,"code":"plan_required","detail":"The workspace's plan does not include this feature.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"read","x-rate-class":"light"}},"/crawls/{crawl_id}/cancel":{"post":{"tags":["Crawl control"],"summary":"Cancel a crawl","description":"Asks for one of your workspace's crawls to stop. Only a crawl that is `pending` or `running` can be cancelled (409 `crawl_not_active` otherwise). A crawl that is queued, or waiting between two parts, ends at once; a running crawl is told to stop and the crawler does so within a few seconds, so the answer is `202 Accepted` and the crawl's `status` becomes `cancelled` shortly after: watch `GET /crawls/{id}`.\n\n**Pages checked so far stay billed.** The crawl is charged for the pages it checked before it stopped, as after a cancel in the dashboard; a crawl cancelled before it started costs nothing. Cancelling does not give credits back.\n\nNeeds the `crawl` scope (a viewer's key cannot). Until starting crawls through the API is switched on, this route answers 404.","operationId":"cancel_crawl","parameters":[{"name":"crawl_id","in":"path","required":true,"schema":{"type":"string","maxLength":64,"description":"The crawl's id.","title":"Crawl Id"},"description":"The crawl's id."}],"responses":{"202":{"description":"Accepted. The body is a `CrawlCancelRequested`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlCancelRequested"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Crawl is not active: The crawl is not pending or running, so there is nothing to cancel; `detail` says what it is.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"crawl_not_active":{"summary":"Crawl is not active","value":{"type":"https://perfbee.com/developers/errors#crawl_not_active","title":"Crawl is not active","status":409,"code":"crawl_not_active","detail":"The crawl is not pending or running, so there is nothing to cancel; `detail` says what it is.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Service busy: The service has no free capacity for this request right now; retry after `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"crawl","x-rate-class":"light"}},"/webhook-endpoints":{"get":{"tags":["Webhooks"],"summary":"List webhook endpoints","description":"Lists the workspace's webhook endpoints, oldest first (at most 5). A single endpoint the dashboard had before is moved into this list the first time it is needed. Needs the `webhooks` scope. The signing secret is never in a list.","operationId":"list_webhook_endpoints","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. A page of `WebhookEndpoint` objects, with `next_cursor` and `has_more`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPage_WebhookEndpoint_"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"webhooks","x-rate-class":"light"},"post":{"tags":["Webhooks"],"summary":"Create a webhook endpoint","description":"Adds an endpoint that receives the events you pick, signed with `PerfBee-Signature`. The answer carries the signing secret: it is shown once, here, and cannot be read again (rotate it to get a new one). The address must be an https URL on a public host. Needs the `webhooks` scope.","operationId":"create_webhook_endpoint","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreate"}}}},"responses":{"201":{"description":"Created. The body is a `WebhookEndpointSecret`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointSecret"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"409":{"description":"Webhook endpoint limit reached: A workspace can have 5 webhook endpoints. Delete one first.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"webhook_endpoint_limit":{"summary":"Webhook endpoint limit reached","value":{"type":"https://perfbee.com/developers/errors#webhook_endpoint_limit","title":"Webhook endpoint limit reached","status":409,"code":"webhook_endpoint_limit","detail":"A workspace can have 5 webhook endpoints. Delete one first.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Invalid webhook URL: The URL must be an https:// address on a public host, without a user name, spaces or quote characters. The host is resolved when the endpoint is saved and again at every delivery; a private or internal address is refused.; Invalid webhook events: `events` must name at least one event from GET /webhook-events, each once.; Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_webhook_url":{"summary":"Invalid webhook URL","value":{"type":"https://perfbee.com/developers/errors#invalid_webhook_url","title":"Invalid webhook URL","status":422,"code":"invalid_webhook_url","detail":"The URL must be an https:// address on a public host, without a user name, spaces or quote characters. The host is resolved when the endpoint is saved and again at every delivery; a private or internal address is refused.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"invalid_webhook_events":{"summary":"Invalid webhook events","value":{"type":"https://perfbee.com/developers/errors#invalid_webhook_events","title":"Invalid webhook events","status":422,"code":"invalid_webhook_events","detail":"`events` must name at least one event from GET /webhook-events, each once.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Webhook signing is not available: Signing secrets cannot be made on this server yet, so an endpoint cannot be created or its secret rotated. Try again later or write to support@perfbee.com.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"webhook_signing_unavailable":{"summary":"Webhook signing is not available","value":{"type":"https://perfbee.com/developers/errors#webhook_signing_unavailable","title":"Webhook signing is not available","status":503,"code":"webhook_signing_unavailable","detail":"Signing secrets cannot be made on this server yet, so an endpoint cannot be created or its secret rotated. Try again later or write to support@perfbee.com.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"webhooks","x-rate-class":"light"}},"/webhook-endpoints/{endpoint_id}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook endpoint","description":"One endpoint of the workspace: where it sends, which events, whether it is paused, how its last delivery went. Needs the `webhooks` scope. The signing secret is never returned.","operationId":"get_webhook_endpoint","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"integer","title":"Endpoint Id"},"description":"The webhook endpoint's id, from `GET /webhook-endpoints`."}],"responses":{"200":{"description":"OK. The body is a `WebhookEndpoint`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"webhooks","x-rate-class":"light"},"patch":{"tags":["Webhooks"],"summary":"Change or pause a webhook endpoint","description":"Changes the fields you send: the address (its delivery history starts again), the events, the note, or `enabled` (false pauses it: nothing is sent while it is paused). Needs the `webhooks` scope.","operationId":"update_webhook_endpoint","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"integer","title":"Endpoint Id"},"description":"The webhook endpoint's id, from `GET /webhook-endpoints`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointUpdate"}}}},"responses":{"200":{"description":"OK. The body is a `WebhookEndpoint`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Invalid webhook URL: The URL must be an https:// address on a public host, without a user name, spaces or quote characters. The host is resolved when the endpoint is saved and again at every delivery; a private or internal address is refused.; Invalid webhook events: `events` must name at least one event from GET /webhook-events, each once.; Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_webhook_url":{"summary":"Invalid webhook URL","value":{"type":"https://perfbee.com/developers/errors#invalid_webhook_url","title":"Invalid webhook URL","status":422,"code":"invalid_webhook_url","detail":"The URL must be an https:// address on a public host, without a user name, spaces or quote characters. The host is resolved when the endpoint is saved and again at every delivery; a private or internal address is refused.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"invalid_webhook_events":{"summary":"Invalid webhook events","value":{"type":"https://perfbee.com/developers/errors#invalid_webhook_events","title":"Invalid webhook events","status":422,"code":"invalid_webhook_events","detail":"`events` must name at least one event from GET /webhook-events, each once.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"webhooks","x-rate-class":"light"},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook endpoint","description":"Removes the endpoint and its delivery list. Nothing is sent to it from now on. Needs the `webhooks` scope.","operationId":"delete_webhook_endpoint","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"integer","title":"Endpoint Id"},"description":"The webhook endpoint's id, from `GET /webhook-endpoints`."}],"responses":{"204":{"description":"Done. There is no body.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"webhooks","x-rate-class":"light"}},"/webhook-endpoints/{endpoint_id}/test":{"post":{"tags":["Webhooks"],"summary":"Send a test event","description":"Sends one `test` event to the endpoint now, signed like a real one, and answers with the delivery: whether it arrived, the receiver's HTTP status and how long it took. A failed test is not retried and does not count towards the endpoint's failure run. Needs the `webhooks` scope.","operationId":"test_webhook_endpoint","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"integer","title":"Endpoint Id"},"description":"The webhook endpoint's id, from `GET /webhook-endpoints`."}],"responses":{"200":{"description":"OK. The body is a `WebhookDelivery`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Service busy: The service has no free capacity for this request right now; retry after `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"webhooks","x-rate-class":"heavy"}},"/webhook-endpoints/{endpoint_id}/rotate-secret":{"post":{"tags":["Webhooks"],"summary":"Rotate the signing secret","description":"Makes a new signing secret and returns it, once. The old secret keeps signing for 24 hours beside the new one (both signatures are sent), so a receiver can switch without a gap. On an endpoint moved from the old single endpoint this also stops the plain `X-PerfBee-Secret` header. Needs the `webhooks` scope.","operationId":"rotate_webhook_secret","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"integer","title":"Endpoint Id"},"description":"The webhook endpoint's id, from `GET /webhook-endpoints`."}],"responses":{"200":{"description":"OK. The body is a `WebhookEndpointSecret`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointSecret"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Webhook signing is not available: Signing secrets cannot be made on this server yet, so an endpoint cannot be created or its secret rotated. Try again later or write to support@perfbee.com.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"webhook_signing_unavailable":{"summary":"Webhook signing is not available","value":{"type":"https://perfbee.com/developers/errors#webhook_signing_unavailable","title":"Webhook signing is not available","status":503,"code":"webhook_signing_unavailable","detail":"Signing secrets cannot be made on this server yet, so an endpoint cannot be created or its secret rotated. Try again later or write to support@perfbee.com.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"webhooks","x-rate-class":"light"}},"/webhook-endpoints/{endpoint_id}/deliveries":{"get":{"tags":["Webhooks"],"summary":"List an endpoint's deliveries","description":"The endpoint's deliveries, newest first, kept for 14 days: one row per event sent to it, with its state, tries and the receiver's answer. A delivery that is not yet delivered carries its `payload` (a failed one for 3 days). Filter with `status`. Needs the `webhooks` scope.","operationId":"list_webhook_deliveries","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"integer","title":"Endpoint Id"},"description":"The webhook endpoint's id, from `GET /webhook-endpoints`."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(pending|delivered|failed|retrying)$"},{"type":"null"}],"description":"Only deliveries in this state: pending, retrying, delivered or failed.","title":"Status"},"description":"Only deliveries in this state: pending, retrying, delivered or failed."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Items per page, 1 to 200.","default":50,"title":"Limit"},"description":"Items per page, 1 to 200."},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The `next_cursor` of the previous page. Opaque: never build one.","title":"Cursor"},"description":"The `next_cursor` of the previous page. Opaque: never build one."}],"responses":{"200":{"description":"OK. A page of `WebhookDelivery` objects, with `next_cursor` and `has_more`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPage_WebhookDelivery_"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"400":{"description":"Invalid cursor: The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_cursor":{"summary":"Invalid cursor","value":{"type":"https://perfbee.com/developers/errors#invalid_cursor","title":"Invalid cursor","status":400,"code":"invalid_cursor","detail":"The cursor was changed, belongs to another endpoint, another set of filters or another workspace. Start the list again without a cursor.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}}},"x-required-scope":"webhooks","x-rate-class":"light"}},"/webhook-endpoints/{endpoint_id}/deliveries/{delivery_id}/redeliver":{"post":{"tags":["Webhooks"],"summary":"Send a failed delivery again","description":"Starts a new chain of attempts for a failed delivery: a new delivery with the same event id and payload, answered at once with state `pending` (the attempts run in the background). Only a failed delivery whose payload is still stored (3 days) can be sent again. Needs the `webhooks` scope.","operationId":"redeliver_webhook_delivery","parameters":[{"name":"endpoint_id","in":"path","required":true,"schema":{"type":"integer","title":"Endpoint Id"},"description":"The webhook endpoint's id, from `GET /webhook-endpoints`."},{"name":"delivery_id","in":"path","required":true,"schema":{"type":"integer","title":"Delivery Id"},"description":"The delivery's id, from `GET /webhook-endpoints/{endpoint_id}/deliveries`."}],"responses":{"202":{"description":"Accepted. The body is a `WebhookDelivery`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"401":{"description":"Invalid API key: The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"invalid_key":{"summary":"Invalid API key","value":{"type":"https://perfbee.com/developers/errors#invalid_key","title":"Invalid API key","status":401,"code":"invalid_key","detail":"The key is missing, malformed, revoked, expired, or its owner left the workspace. Send `Authorization: Bearer pbk_...`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"WWW-Authenticate":{"$ref":"#/components/headers/WWW-Authenticate"}}},"403":{"description":"Forbidden: The key is valid but the API is not available to its workspace yet.; Scope required: The key lacks the scope this endpoint needs; `required_scope` names it.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"forbidden":{"summary":"Forbidden","value":{"type":"https://perfbee.com/developers/errors#forbidden","title":"Forbidden","status":403,"code":"forbidden","detail":"The key is valid but the API is not available to its workspace yet.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"scope_required":{"summary":"Scope required","value":{"type":"https://perfbee.com/developers/errors#scope_required","title":"Scope required","status":403,"code":"scope_required","detail":"The key lacks the scope this endpoint needs; `required_scope` names it.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{}},"404":{"description":"Not found: The object does not exist, or belongs to another workspace (the two are never told apart).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"not_found":{"summary":"Not found","value":{"type":"https://perfbee.com/developers/errors#not_found","title":"Not found","status":404,"code":"not_found","detail":"The object does not exist, or belongs to another workspace (the two are never told apart).","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"409":{"description":"Delivery in progress: The delivery is still pending or being retried. Wait until it is delivered or failed.; Payload is no longer stored: Only a failed delivery keeps its payload, for 3 days; a delivered event, or an older failure, cannot be sent again. Read the state through the API instead.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"delivery_in_progress":{"summary":"Delivery in progress","value":{"type":"https://perfbee.com/developers/errors#delivery_in_progress","title":"Delivery in progress","status":409,"code":"delivery_in_progress","detail":"The delivery is still pending or being retried. Wait until it is delivered or failed.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"delivery_payload_unavailable":{"summary":"Payload is no longer stored","value":{"type":"https://perfbee.com/developers/errors#delivery_payload_unavailable","title":"Payload is no longer stored","status":409,"code":"delivery_payload_unavailable","detail":"Only a failed delivery keeps its payload, for 3 days; a delivered event, or an older failure, cannot be sent again. Read the state through the API instead.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"422":{"description":"Validation failed: A parameter or body field is missing or has a wrong value; `errors` lists them.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"validation_error":{"summary":"Validation failed","value":{"type":"https://perfbee.com/developers/errors#validation_error","title":"Validation failed","status":422,"code":"validation_error","detail":"A parameter or body field is missing or has a wrong value; `errors` lists them.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"429":{"description":"Rate limit exceeded: Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"rate_limited":{"summary":"Rate limit exceeded","value":{"type":"https://perfbee.com/developers/errors#rate_limited","title":"Rate limit exceeded","status":429,"code":"rate_limited","detail":"Too many requests this minute for the key, the workspace or the network; wait for `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}},"too_many_heavy_requests":{"summary":"Too many heavy calls at once","value":{"type":"https://perfbee.com/developers/errors#too_many_heavy_requests","title":"Too many heavy calls at once","status":429,"code":"too_many_heavy_requests","detail":"Too many heavy calls of this workspace (lists of links, issues and pages, diffs, exports, webhook tests) are running at the same time. Send them one after another; retry after `Retry-After` seconds.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}},"500":{"description":"Internal error: Something failed on our side; the error is logged under `request_id`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"internal_error":{"summary":"Internal error","value":{"type":"https://perfbee.com/developers/errors#internal_error","title":"Internal error","status":500,"code":"internal_error","detail":"Something failed on our side; the error is logged under `request_id`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"}}},"503":{"description":"Service busy: The service has no free capacity for this request right now; retry after `Retry-After`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetail"},"examples":{"capacity_busy":{"summary":"Service busy","value":{"type":"https://perfbee.com/developers/errors#capacity_busy","title":"Service busy","status":503,"code":"capacity_busy","detail":"The service has no free capacity for this request right now; retry after `Retry-After`.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10"}}}}},"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"Retry-After":{"$ref":"#/components/headers/Retry-After"}}}},"x-required-scope":"webhooks","x-rate-class":"heavy"}}},"components":{"schemas":{"AiBot":{"properties":{"token":{"type":"string","title":"Token","description":"The bot's robots.txt name."},"vendor":{"type":"string","title":"Vendor","description":"Who runs it."},"purpose":{"type":"string","title":"Purpose","description":"search, user (fetches a page when a person asks) or training."},"feeds":{"type":"string","title":"Feeds","description":"What it feeds (ChatGPT search, AI Overviews...)."},"kind":{"type":"string","title":"Kind","description":"crawler, or token (a robots.txt name another crawler obeys)."},"robots_binding":{"type":"boolean","title":"Robots Binding","description":"False when the vendor says the agent may ignore robots.txt (a Disallow is then a request)."},"robots_note":{"type":"string","title":"Robots Note","description":"A note on how the vendor treats robots.txt; may be empty."},"robots":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Robots","description":"What the site's robots.txt says for this bot; null when it was not read."},"reachable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Reachable","description":"False when robots.txt disallows the homepage for it; null when unknown."}},"type":"object","required":["token","vendor","purpose","feeds","kind","robots_binding","robots_note","robots","reachable"],"title":"AiBot"},"AiIssue":{"properties":{"code":{"type":"string","title":"Code","description":"The issue's stable code (noindex, nosnippet, js_shell...)."},"label":{"type":"string","title":"Label","description":"The issue in words."},"severity":{"type":"string","title":"Severity","description":"error or warning."},"help":{"type":"string","title":"Help","description":"What it means and how to fix it."},"count":{"type":"integer","title":"Count","description":"Pages with the issue (distinct URLs)."}},"type":"object","required":["code","label","severity","help","count"],"title":"AiIssue"},"AiPages":{"properties":{"total":{"type":"integer","title":"Total","description":"Pages that answered 200."},"quotable":{"type":"integer","title":"Quotable","description":"Pages without an issue that keeps them out of AI answers."},"issues":{"items":{"$ref":"#/components/schemas/AiIssue"},"type":"array","title":"Issues","description":"The issues found, with exact page counts."}},"type":"object","required":["total","quotable","issues"],"title":"AiPages"},"AiReadiness":{"properties":{"status":{"type":"string","title":"Status","description":"ready. (A crawl whose report is still being written answers 409 crawl_not_ready.)"},"bots":{"items":{"$ref":"#/components/schemas/AiBot"},"type":"array","title":"Bots","description":"One row per AI bot: can it reach the site, from robots.txt."},"robots":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Robots","description":"The site's robots.txt as read: issues, Content-Signal lines, CDN hints."},"probe":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Probe","description":"The sample-page fetch of the report (sections as stored); may be null."},"render":{"items":{"type":"object"},"type":"array","title":"Render","description":"Sample pages: what the raw HTML holds compared with the rendered page."},"site":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Site","description":"Site-level checks: brand identity, llms.txt and the like (sections as stored)."},"checked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checked At","description":"When the report was made."},"pages":{"$ref":"#/components/schemas/AiPages"}},"type":"object","required":["status","bots","robots","probe","render","site","checked_at","pages"],"title":"AiReadiness","description":"The AI Search Readiness report of one detailed crawl, as the dashboard shows it.","example":{"bots":[{"feeds":"ChatGPT search","kind":"crawler","purpose":"search","reachable":true,"robots":{"home_allowed":true},"robots_binding":true,"robots_note":"","token":"OAI-SearchBot","vendor":"OpenAI"}],"checked_at":"2026-10-30T02:16:10+00:00","pages":{"issues":[{"code":"noindex","count":32,"help":"noindex in the robots meta tag or X-Robots-Tag header.","label":"Not indexable","severity":"error"}],"quotable":1588,"total":1620},"render":[],"robots":{"issues":[]},"site":{"llms_txt":false},"status":"ready"}},"AiReadinessTotals":{"properties":{"total":{"type":"integer","title":"Total","description":"AI readiness issues found, one per page and code."},"by_code":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Code","description":"Pages per issue code (only codes that were found)."}},"type":"object","required":["total","by_code"],"title":"AiReadinessTotals"},"ApiFlags":{"properties":{"crawl_enabled":{"type":"boolean","title":"Crawl Enabled","description":"True when POST /crawls (start and cancel a crawl) is available."},"webhooks_v2":{"type":"boolean","title":"Webhooks V2","description":"True when signed webhook endpoints can be managed through the API."}},"type":"object","required":["crawl_enabled","webhooks_v2"],"title":"ApiFlags"},"ChangeCounts":{"properties":{"new":{"type":"integer","title":"New","description":"Seen for the first time by the newest crawl."},"changed":{"type":"integer","title":"Changed","description":"Whose status changed in the newest crawl."}},"type":"object","required":["new","changed"],"title":"ChangeCounts"},"Crawl":{"properties":{"id":{"type":"string","title":"Id","description":"The crawl's id (a UUID)."},"site_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Site Id","description":"The most specific site of yours this crawl belongs to; null when the site was removed."},"url":{"type":"string","title":"Url","description":"The address the crawl started from."},"mode":{"type":"string","title":"Mode","description":"fast (links and status only) or full (SEO data and AI readiness too)."},"status":{"type":"string","title":"Status","description":"pending, running, completed, failed, cancelled or partial. New values may appear."},"started_via":{"type":"string","enum":["dashboard","schedule","mcp","api"],"title":"Started Via","description":"What started the crawl."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the crawl was queued."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"When the crawler started; null while queued."},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At","description":"When it ended; null while pending or running."},"duration_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Seconds","description":"How long it ran, once it ended."},"max_pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Pages","description":"The page limit the crawl was started with; null = no limit."},"pages_checked":{"type":"integer","title":"Pages Checked","description":"Pages read (final once the crawl ended; see `progress` while it runs)."},"links_checked":{"type":"integer","title":"Links Checked","description":"URLs checked, links and files included."},"broken_count":{"type":"integer","title":"Broken Count","description":"Broken URLs found."},"working_count":{"type":"integer","title":"Working Count","description":"URLs that worked."},"results":{"anyOf":[{"$ref":"#/components/schemas/CrawlResults"},{"type":"null"}],"description":"The result buckets stored when the crawl ended; null while it runs and for crawls from before 2026-10-20."},"close_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Close Reason","description":"Why the crawler stopped: finished, closespider_pagecount, blocked, rate_limited, credit_limit... New values may appear."},"crawl_scope":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Crawl Scope","description":"What the crawl covered (checks on or off, sitemap, render mode, folder, list mode...). Keys may be added."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a crawl that stopped early stopped, in a sentence; null otherwise."},"credits_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Credits Charged","description":"Credits this crawl cost so far; null when nothing was charged (queued, free, or nothing checked)."},"progress":{"anyOf":[{"$ref":"#/components/schemas/CrawlProgress"},{"type":"null"}],"description":"Live counters while the crawl is pending or running; null otherwise."},"processing":{"$ref":"#/components/schemas/CrawlProcessing"},"report_url":{"type":"string","title":"Report Url","description":"The same crawl in the dashboard."}},"type":"object","required":["id","site_id","url","mode","status","started_via","created_at","started_at","completed_at","duration_seconds","max_pages","pages_checked","links_checked","broken_count","working_count","results","close_reason","crawl_scope","error","credits_charged","progress","processing","report_url"],"title":"Crawl","example":{"broken_count":12,"close_reason":"finished","completed_at":"2026-10-30T02:14:51Z","crawl_scope":{"check_external":false,"check_internal":true,"crawl_sitemap":true,"folder":"","list_mode":false,"render_js":false},"created_at":"2026-10-30T02:00:00Z","credits_charged":3680.0,"duration_seconds":887.2,"id":"5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","links_checked":9215,"max_pages":5000,"mode":"full","pages_checked":1840,"processing":{"fixes":"done","inventory":"done"},"report_url":"https://dashboard.perfbee.com/#/brokenLinks?scan=5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","results":{"broken":12,"not_checked":23,"ok":9020,"redirects":160,"total":9215},"site_id":7,"started_at":"2026-10-30T02:00:04Z","started_via":"schedule","status":"completed","url":"https://www.example.com/","working_count":9020}},"CrawlCancelRequested":{"properties":{"id":{"type":"string","title":"Id","description":"The crawl's id."},"status":{"type":"string","title":"Status","description":"`cancelled` when the crawl ended at once (it was queued or waiting for its next part); `pending` or `running` while the crawler is stopping it."},"cancelled":{"type":"boolean","title":"Cancelled","description":"True when the crawl is already cancelled; false when the crawler has been told and stops within a few seconds."},"message":{"type":"string","title":"Message","description":"What happens next, in a sentence."}},"type":"object","required":["id","status","cancelled","message"],"title":"CrawlCancelRequested","description":"The answer to a cancel: what became of the crawl, and what happens next.","example":{"cancelled":false,"id":"3f2b8c1e-5d47-4a0b-9a6e-1c7d2e8f4b90","message":"The crawler was told to stop. It saves the pages it checked, which stay billed. Poll the crawl until its status is cancelled.","status":"running"}},"CrawlCredits":{"properties":{"per_page":{"type":"number","title":"Per Page","description":"Credits per page at the rate this crawl is billed (owned-site and render rates included)."},"max_cost":{"type":"number","title":"Max Cost","description":"The most the crawl can cost: max_pages times per_page. It is charged when the crawl ends, for the pages actually checked."},"remaining_before":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Remaining Before","description":"Credits the workspace had left this month before this crawl; null = unlimited."},"held_by_running_crawls":{"type":"number","title":"Held By Running Crawls","description":"Credits the workspace's other running API crawls may still spend."}},"type":"object","required":["per_page","max_cost","remaining_before","held_by_running_crawls"],"title":"CrawlCredits"},"CrawlDiff":{"properties":{"crawl_id":{"type":"string","title":"Crawl Id","description":"The crawl that was asked about (the current one)."},"has_previous":{"type":"boolean","title":"Has Previous","description":"False when there is no earlier completed crawl of the site in the same mode: everything else is then null."},"current":{"$ref":"#/components/schemas/CrawlRef"},"previous":{"anyOf":[{"$ref":"#/components/schemas/CrawlRef"},{"type":"null"}],"description":"The crawl it was compared with."},"compared":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compared","description":"What was compared: `pages` (pages and links) or `broken_links`."},"pages_compared":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Pages Compared","description":"False when only broken links were compared: a fast crawl, or crawls too big to compare page by page (`pages_note` says which)."},"pages_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pages Note","description":"Why pages were not compared."},"coverage_gap":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coverage Gap","description":"Why pages the current crawl did not reach are not listed as disappeared: `stopped` (it ended early) or `scope` (it covered less than the previous crawl)."},"summary":{"anyOf":[{"$ref":"#/components/schemas/DiffSummary"},{"type":"null"}]},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"`stored` (counted when the crawl was processed) or `computed` (counted for this request)."},"computed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Computed At","description":"When the summary was counted (UTC)."},"lists":{"anyOf":[{"$ref":"#/components/schemas/DiffLists"},{"type":"null"}],"description":"Only with `include=lists`."},"truncated":{"anyOf":[{"additionalProperties":{"type":"boolean"},"type":"object"},{"type":"null"}],"title":"Truncated","description":"With `lists`: which lists were cut at `limit`."}},"type":"object","required":["crawl_id","has_previous","current"],"title":"CrawlDiff","example":{"compared":"pages","computed_at":"2026-10-31T09:14:02Z","crawl_id":"0b6c0f5e-6f3c-4a0e-9a53-2f6f3a3c7c11","current":{"completed_at":"2026-10-31T09:00:00Z","crawl_id":"0b6c0f5e-6f3c-4a0e-9a53-2f6f3a3c7c11","pages":1840},"has_previous":true,"pages_compared":true,"previous":{"completed_at":"2026-10-30T09:00:00Z","crawl_id":"8d1d7a2e-2a43-45a8-b7d1-6d0c3a8f9e02","pages":1832},"source":"stored","summary":{"changed":31,"disappeared":0,"fixed_broken":5,"new_broken":2,"new_pages":8,"not_reached":0,"not_rechecked":0,"persistent_broken":17}}},"CrawlPage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Crawl"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."}},"type":"object","required":["data","has_more"],"title":"CrawlPage","description":"A page of crawls, newest first.","example":{"data":[{"broken_count":12,"close_reason":"finished","completed_at":"2026-10-30T02:14:51Z","crawl_scope":{"check_external":false,"check_internal":true,"crawl_sitemap":true,"folder":"","list_mode":false,"render_js":false},"created_at":"2026-10-30T02:00:00Z","credits_charged":3680.0,"duration_seconds":887.2,"id":"5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","links_checked":9215,"max_pages":5000,"mode":"full","pages_checked":1840,"processing":{"fixes":"done","inventory":"done"},"report_url":"https://dashboard.perfbee.com/#/brokenLinks?scan=5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","results":{"broken":12,"not_checked":23,"ok":9020,"redirects":160,"total":9215},"site_id":7,"started_at":"2026-10-30T02:00:04Z","started_via":"schedule","status":"completed","url":"https://www.example.com/","working_count":9020}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"CrawlProcessing":{"properties":{"inventory":{"type":"string","enum":["pending","done","failed","not_applicable"],"title":"Inventory","description":"Site Pages (GET /sites/{site_id}/pages) hold this crawl's data. pending = on its way, failed = the sync failed (it is retried for 48 hours), not_applicable = no site of yours takes this crawl in."},"fixes":{"type":"string","enum":["pending","done","skipped","not_applicable"],"title":"Fixes","description":"The fix list was refreshed from this crawl. skipped = the inventory sync failed, so no refresh ran; not_applicable = Fixes are off or no site takes the crawl in. The `scan_data_ready` webhook is the exact moment."}},"type":"object","required":["inventory","fixes"],"title":"CrawlProcessing","description":"Where the crawl's data stands after the crawl itself. A crawl is `completed` before its pages and fixes are ready."},"CrawlProgress":{"properties":{"pages_checked":{"type":"integer","title":"Pages Checked","description":"Pages read so far."},"links_checked":{"type":"integer","title":"Links Checked","description":"Links and files checked so far."},"broken_count":{"type":"integer","title":"Broken Count","description":"Broken URLs found so far."},"max_pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Pages","description":"The page limit of the crawl; null = no limit."},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At","description":"When the crawler last reported (a heartbeat each minute)."}},"type":"object","required":["pages_checked","links_checked","broken_count","max_pages","updated_at"],"title":"CrawlProgress","description":"A running crawl's live counters (they stop being kept a day after the crawl)."},"CrawlRef":{"properties":{"crawl_id":{"type":"string","title":"Crawl Id","description":"The crawl's id."},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At","description":"When it completed (UTC)."},"pages":{"type":"integer","title":"Pages","description":"Pages it checked."}},"type":"object","required":["crawl_id","pages"],"title":"CrawlRef"},"CrawlResults":{"properties":{"total":{"type":"integer","title":"Total","description":"Checked URLs: ok + redirects + broken + not_checked."},"ok":{"type":"integer","title":"Ok","description":"URLs that answered normally."},"redirects":{"type":"integer","title":"Redirects","description":"URLs that redirected."},"broken":{"type":"integer","title":"Broken","description":"URLs that are broken (404, 5xx, no answer...)."},"not_checked":{"type":"integer","title":"Not Checked","description":"URLs the crawler could not check (a bot wall, robots.txt, a timeout...); never billed, never broken."}},"type":"object","required":["total","ok","redirects","broken","not_checked"],"title":"CrawlResults","description":"Every URL the crawl checked, in exactly one bucket (stored when the crawl ended)."},"CrawlStarted":{"properties":{"id":{"type":"string","title":"Id","description":"The crawl's id (a UUID)."},"site_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Site Id","description":"The most specific site of yours this crawl belongs to; null when the site was removed."},"url":{"type":"string","title":"Url","description":"The address the crawl started from."},"mode":{"type":"string","title":"Mode","description":"fast (links and status only) or full (SEO data and AI readiness too)."},"status":{"type":"string","title":"Status","description":"pending, running, completed, failed, cancelled or partial. New values may appear."},"started_via":{"type":"string","enum":["dashboard","schedule","mcp","api"],"title":"Started Via","description":"What started the crawl."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the crawl was queued."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"When the crawler started; null while queued."},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At","description":"When it ended; null while pending or running."},"duration_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration Seconds","description":"How long it ran, once it ended."},"max_pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Pages","description":"The page limit the crawl was started with; null = no limit."},"pages_checked":{"type":"integer","title":"Pages Checked","description":"Pages read (final once the crawl ended; see `progress` while it runs)."},"links_checked":{"type":"integer","title":"Links Checked","description":"URLs checked, links and files included."},"broken_count":{"type":"integer","title":"Broken Count","description":"Broken URLs found."},"working_count":{"type":"integer","title":"Working Count","description":"URLs that worked."},"results":{"anyOf":[{"$ref":"#/components/schemas/CrawlResults"},{"type":"null"}],"description":"The result buckets stored when the crawl ended; null while it runs and for crawls from before 2026-10-20."},"close_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Close Reason","description":"Why the crawler stopped: finished, closespider_pagecount, blocked, rate_limited, credit_limit... New values may appear."},"crawl_scope":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Crawl Scope","description":"What the crawl covered (checks on or off, sitemap, render mode, folder, list mode...). Keys may be added."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why a crawl that stopped early stopped, in a sentence; null otherwise."},"credits_charged":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Credits Charged","description":"Credits this crawl cost so far; null when nothing was charged (queued, free, or nothing checked)."},"progress":{"anyOf":[{"$ref":"#/components/schemas/CrawlProgress"},{"type":"null"}],"description":"Live counters while the crawl is pending or running; null otherwise."},"processing":{"$ref":"#/components/schemas/CrawlProcessing"},"report_url":{"type":"string","title":"Report Url","description":"The same crawl in the dashboard."},"render_js":{"type":"boolean","title":"Render Js","description":"True when pages are rendered with JavaScript."},"credits":{"anyOf":[{"$ref":"#/components/schemas/CrawlCredits"},{"type":"null"}],"description":"The credit estimate made when this request started the crawl; null on a replay."}},"type":"object","required":["id","site_id","url","mode","status","started_via","created_at","started_at","completed_at","duration_seconds","max_pages","pages_checked","links_checked","broken_count","working_count","results","close_reason","crawl_scope","error","credits_charged","progress","processing","report_url","render_js"],"title":"CrawlStarted","description":"The crawl as `POST /crawls` (and an idempotent replay of it) answers it: the same object `GET /crawls/{id}` returns,\nplus the render switch the request set and the credit estimate made when it started. Poll `GET /crawls/{id}` for progress.","example":{"broken_count":0,"created_at":"2026-10-31T09:12:44Z","credits":{"held_by_running_crawls":0.0,"max_cost":250.0,"per_page":0.5,"remaining_before":8759.5},"id":"3f2b8c1e-5d47-4a0b-9a6e-1c7d2e8f4b90","links_checked":0,"max_pages":500,"mode":"fast","pages_checked":0,"processing":{"fixes":"pending","inventory":"pending"},"render_js":false,"report_url":"https://dashboard.perfbee.com/#/brokenLinks?scan=3f2b8c1e-5d47-4a0b-9a6e-1c7d2e8f4b90","site_id":12,"started_via":"api","status":"pending","url":"https://www.example.com","working_count":0}},"CrawlSummary":{"properties":{"id":{"type":"string","title":"Id","description":"The crawl's id (a UUID): pass it to GET /crawls/{crawl_id}."},"url":{"type":"string","title":"Url","description":"The address the crawl started from."},"status":{"type":"string","title":"Status","description":"pending, running, completed, failed, cancelled or partial. New values may appear."},"mode":{"type":"string","title":"Mode","description":"fast (links and status only) or full (SEO data and AI readiness too)."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"When the crawler started; null while the crawl waits in the queue."},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At","description":"When the crawl ended; null while it is pending or running."},"pages_checked":{"type":"integer","title":"Pages Checked","description":"Pages the crawl read."},"broken_count":{"type":"integer","title":"Broken Count","description":"Broken URLs the crawl found."},"report_url":{"type":"string","title":"Report Url","description":"The same crawl in the dashboard."}},"type":"object","required":["id","url","status","mode","started_at","completed_at","pages_checked","broken_count","report_url"],"title":"CrawlSummary","description":"A crawl in one line: what a site shows for its latest crawl."},"CreditCosts":{"properties":{"scan_fast":{"type":"number","title":"Scan Fast","description":"Credits per page of a fast crawl."},"scan_detailed":{"type":"number","title":"Scan Detailed","description":"Credits per page of a detailed crawl."},"scan_js_rendering":{"type":"number","title":"Scan Js Rendering","description":"Credits per page rendered with JavaScript."},"scan_fast_owned":{"type":"number","title":"Scan Fast Owned","description":"Per page of a fast crawl of a site you own (verified)."},"scan_detailed_owned":{"type":"number","title":"Scan Detailed Owned","description":"Per page of a detailed crawl of a site you own."},"scan_js_rendering_owned":{"type":"number","title":"Scan Js Rendering Owned","description":"Per rendered page of a site you own."}},"type":"object","required":["scan_fast","scan_detailed","scan_js_rendering","scan_fast_owned","scan_detailed_owned","scan_js_rendering_owned"],"title":"CreditCosts"},"CreditsInfo":{"properties":{"period":{"type":"string","title":"Period","description":"The month the numbers are for (YYYY-MM, UTC)."},"used":{"type":"number","title":"Used","description":"Credits spent this month."},"limit":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Limit","description":"Credits the plan gives this month, bonus included; null = unlimited."},"remaining":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Remaining","description":"Credits left this month; null = unlimited."},"bonus":{"type":"number","title":"Bonus","description":"Bonus credits added to this month."},"unlimited":{"type":"boolean","title":"Unlimited","description":"True when the plan has no credit limit."},"costs":{"$ref":"#/components/schemas/CreditCosts"}},"type":"object","required":["period","used","limit","remaining","bonus","unlimited","costs"],"title":"CreditsInfo"},"CursorPage_IssueType_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/IssueType"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."}},"type":"object","required":["data","has_more"],"title":"CursorPage[IssueType]","example":{"data":[{"category":"content","code":"missing_title","fix":"Give every page a short, unique title.","help":"The page has no <title> element.","label":"Missing title","severity":"error","why":"Search results show the title; without one they guess."}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"CursorPage_WebhookDelivery_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookDelivery"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."}},"type":"object","required":["data","has_more"],"title":"CursorPage[WebhookDelivery]","example":{"data":[{"attempt":5,"created_at":"2026-11-01T09:30:12Z","duration_ms":412,"event":"scan_data_ready","event_id":"evt_5f0c2b7e9a1d4c3e8b6a7d9f01234567","http_status":503,"id":4182,"max_attempts":5,"payload":{"api_version":"v1","data":{"crawl_id":"0f7c9a52-3d4b-4a39-8c0e-5e2a9d1b6f10","mode":"full","site_id":7},"event":"scan_data_ready","event_description":"Crawl data ready","id":"evt_5f0c2b7e9a1d4c3e8b6a7d9f01234567","timestamp":"2026-11-01T09:30:12.512Z"},"status":"failed"}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"CursorPage_WebhookEndpoint_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookEndpoint"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."}},"type":"object","required":["data","has_more"],"title":"CursorPage[WebhookEndpoint]","example":{"data":[{"consecutive_failures":0,"created_at":"2026-10-20T14:02:00Z","description":"CI gate","enabled":true,"events":["scan_data_ready","scan_failed"],"id":3,"last_delivery_at":"2026-11-01T09:30:12Z","last_status":"delivered","signed":true,"source":"api","url":"https://hooks.example.com/perfbee"}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"CursorPage_WebhookEventType_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/WebhookEventType"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."}},"type":"object","required":["data","has_more"],"title":"CursorPage[WebhookEventType]","example":{"data":[{"description":"Every finished crawl, with or without broken links.","event":"scan_completed","group":"Site Crawler","label":"Scan completed"}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"DiffLists":{"properties":{"new_pages":{"items":{"$ref":"#/components/schemas/PageRef"},"type":"array","title":"New Pages","default":[]},"disappeared":{"items":{"$ref":"#/components/schemas/GonePage"},"type":"array","title":"Disappeared","default":[]},"changed":{"items":{"$ref":"#/components/schemas/PageChange"},"type":"array","title":"Changed","default":[]},"new_broken":{"items":{"type":"string"},"type":"array","title":"New Broken","default":[]},"fixed_broken":{"items":{"type":"string"},"type":"array","title":"Fixed Broken","default":[]}},"type":"object","title":"DiffLists","description":"The first `limit` of each list, URL order. The summary has the true counts."},"DiffSummary":{"properties":{"new_pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"New Pages","description":"Pages not in the previous crawl. Null when pages were not compared."},"disappeared":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Disappeared","description":"Pages of the previous crawl that now answer an error or a redirect, or are gone from a crawl that covered the whole site. Null when pages were not compared."},"redirected":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Redirected","description":"Of the disappeared pages, the ones that now redirect (often on purpose). Absent when redirects were not counted; null when pages were not compared."},"changed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Changed","description":"Pages whose status, title, meta description, indexability or canonical changed. Null when pages were not compared."},"new_broken":{"type":"integer","title":"New Broken","description":"Links broken now that were not broken in the previous crawl."},"fixed_broken":{"type":"integer","title":"Fixed Broken","description":"Links broken before that were checked again and work."},"persistent_broken":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Persistent Broken","description":"Links broken in both crawls."},"not_reached":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Not Reached","description":"Pages of the previous crawl this one did not reach: not counted as gone. Null when pages were not compared."},"not_rechecked":{"type":"integer","title":"Not Rechecked","description":"Links broken before that this crawl did not check again: not counted as fixed."}},"type":"object","required":["new_broken","fixed_broken","not_rechecked"],"title":"DiffSummary","description":"Counts of what changed. Only what the current crawl saw counts as a change: a link broken last time is `fixed`\nonly when this crawl checked it again and it works; one it did not check again is `not_rechecked`."},"Feed":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"dataset":{"type":"string","title":"Dataset"},"dataset_label":{"type":"string","title":"Dataset Label"},"site_id":{"type":"integer","title":"Site Id"},"site_url":{"type":"string","title":"Site Url"},"prefix":{"type":"string","title":"Prefix","description":"The first characters of the link's secret (pbf_xxxxxxxx): enough to recognise it."},"status":{"type":"string","title":"Status","description":"active, revoked or expired."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"A link stops working after a year."},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At","description":"When a sheet last read it."},"use_count":{"type":"integer","title":"Use Count","description":"How many times it was read."}},"type":"object","required":["id","name","dataset","dataset_label","site_id","site_url","prefix","status","created_at","expires_at","last_used_at","use_count"],"title":"Feed","example":{"created_at":"2026-10-31T09:12:00Z","dataset":"broken-links","dataset_label":"Broken links","expires_at":"2027-10-31T09:12:00Z","id":9,"name":"Broken links: example.com","prefix":"pbf_k3x9a7bq","site_id":12,"site_url":"https://www.example.com","status":"active","use_count":0}},"FeedCreate":{"properties":{"dataset":{"type":"string","enum":["crawl-history","broken-links","all-urls","seo","site-pages"],"title":"Dataset","description":"Which table the link serves: crawl-history, broken-links, all-urls, seo, site-pages."},"site_id":{"type":"integer","minimum":1.0,"title":"Site Id","description":"One of the workspace's sites (`GET /sites`)."},"name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Name","description":"A name to recognise the link by; the dataset and site by default."},"filters":{"anyOf":[{"$ref":"#/components/schemas/FeedFilters"},{"type":"null"}],"description":"Only for the `site-pages` dataset."}},"additionalProperties":false,"type":"object","required":["dataset","site_id"],"title":"FeedCreate","example":{"dataset":"site-pages","filters":{"status":"broken","view":"pages"},"name":"Broken pages","site_id":12}},"FeedCreated":{"properties":{"id":{"type":"integer","title":"Id"},"name":{"type":"string","title":"Name"},"dataset":{"type":"string","title":"Dataset"},"dataset_label":{"type":"string","title":"Dataset Label"},"site_id":{"type":"integer","title":"Site Id"},"site_url":{"type":"string","title":"Site Url"},"prefix":{"type":"string","title":"Prefix","description":"The first characters of the link's secret (pbf_xxxxxxxx): enough to recognise it."},"status":{"type":"string","title":"Status","description":"active, revoked or expired."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"A link stops working after a year."},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At","description":"When a sheet last read it."},"use_count":{"type":"integer","title":"Use Count","description":"How many times it was read."},"url":{"type":"string","title":"Url","description":"The link: anyone who has it can read the data until it is revoked."},"formula":{"type":"string","title":"Formula","description":"The same link as a Google Sheets formula."}},"type":"object","required":["id","name","dataset","dataset_label","site_id","site_url","prefix","status","created_at","expires_at","last_used_at","use_count","url","formula"],"title":"FeedCreated","description":"The feed and its link. This is the only time the link is shown: keep it like a password.","example":{"created_at":"2026-10-31T09:12:00Z","dataset":"broken-links","dataset_label":"Broken links","expires_at":"2027-10-31T09:12:00Z","formula":"=IMPORTDATA(\"https://dashboard.perfbee.com/feeds/pbf_k3x9a7bq_QmZ0a9xVn2pYf3Lr8sTq1uWb4cXd6eHg7iJ.csv\")","id":9,"name":"Broken links: example.com","prefix":"pbf_k3x9a7bq","site_id":12,"site_url":"https://www.example.com","status":"active","url":"https://dashboard.perfbee.com/feeds/pbf_k3x9a7bq_QmZ0a9xVn2pYf3Lr8sTq1uWb4cXd6eHg7iJ.csv","use_count":0}},"FeedFilters":{"properties":{"view":{"type":"string","enum":["pages","resources","links_out","missing"],"title":"View","description":"pages, resources, links_out or missing.","default":"pages"},"status":{"anyOf":[{"type":"string","enum":["ok","redirect","broken","gone","not_checked","unknown"]},{"type":"null"}],"title":"Status"},"type":{"anyOf":[{"type":"string","enum":["page","document","other","image","css","js","font","video","iframe","audio","embed"]},{"type":"null"}],"title":"Type"},"indexability":{"anyOf":[{"type":"string","enum":["indexable","non_indexable","unknown"]},{"type":"null"}],"title":"Indexability"},"issue":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Issue","description":"An issue code from `GET /issue-types`."},"change":{"anyOf":[{"type":"string","enum":["new","changed"]},{"type":"null"}],"title":"Change"},"resolved":{"type":"string","enum":["show","hide","only"],"title":"Resolved","default":"show"},"prefix":{"type":"string","maxLength":2000,"title":"Prefix","description":"Only URLs that start with this.","default":""},"q":{"type":"string","maxLength":200,"title":"Q","description":"Only URLs that contain this.","default":""},"sort":{"type":"string","enum":["url","status","inlinks","depth","response_time","word_count","last_seen","first_seen"],"title":"Sort","default":"url"},"order":{"type":"string","enum":["asc","desc"],"title":"Order","default":"asc"}},"additionalProperties":false,"type":"object","title":"FeedFilters","description":"The Site Pages view and filters a `site-pages` feed serves, named as in `GET /sites/{site_id}/pages` (and with a\nsort, since a sheet is read in its stored order)."},"FeedList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Feed"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."}},"type":"object","required":["data","has_more"],"title":"FeedList","description":"The workspace's live links, newest first (owners and admins see all, others their own); the links themselves are never listed.","example":{"data":[{"created_at":"2026-10-31T09:12:00Z","dataset":"broken-links","dataset_label":"Broken links","expires_at":"2027-10-31T09:12:00Z","id":9,"name":"Broken links: example.com","prefix":"pbf_k3x9a7bq","site_id":12,"site_url":"https://www.example.com","status":"active","use_count":0}],"has_more":false}},"FieldChange":{"properties":{"previous":{"anyOf":[{"type":"boolean"},{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Previous"},"current":{"anyOf":[{"type":"boolean"},{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Current"}},"type":"object","title":"FieldChange"},"Fix":{"properties":{"id":{"type":"integer","title":"Id"},"code":{"type":"string","title":"Code","description":"The issue code. Page issue codes are in `GET /issue-types`; link fixes use broken_link, broken_external_link and broken_sitemap_url. Ignore codes you do not know."},"label":{"type":"string","title":"Label","description":"The issue in words."},"severity":{"type":"string","title":"Severity","description":"error, warning or info."},"kind":{"type":"string","title":"Kind","description":"site (the whole site), template, pages (separate pages) or link (one broken URL)."},"status":{"type":"string","title":"Status","description":"open, regressed (it came back), checking, looks_fixed, resolved or stale."},"pages":{"type":"integer","title":"Pages","description":"Pages the fix touches (for a link fix: pages that link to the broken URL)."},"template_pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Template Pages","description":"Pages of the template, when the fix is a template's."},"score":{"type":"number","title":"Score","description":"Ranks the fix against the site's others; for ordering only."},"rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rank","description":"Its place in the site's open list; null for a fix that is not open or is set aside."},"scope":{"type":"string","title":"Scope","description":"Where the fix is, in one line."},"template":{"anyOf":[{"$ref":"#/components/schemas/FixTemplate"},{"type":"null"}]},"target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target","description":"For a link fix, the broken URL."},"target_page_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Target Page Id","description":"That URL's id for `GET /sites/{site_id}/pages/{page_id}`; null when it left the inventory."},"first_seen_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Seen At"},"resolved_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved At"},"resolved_by":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved By","description":"scan, check or marked."},"decision":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decision","description":"What the team decided in the dashboard: accepted, wont_fix or snoozed (until the next crawl); null = nothing."},"decided_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decided At"},"decision_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Decision Note"},"last_check":{"anyOf":[{"$ref":"#/components/schemas/FixCheck"},{"type":"null"}]}},"type":"object","required":["id","code","label","severity","kind","status","pages","template_pages","score","rank","scope","template","target","target_page_id","first_seen_at","resolved_at","resolved_by","decision","decided_at","decision_note","last_check"],"title":"Fix","description":"One thing to fix: an issue on a template, on the whole site, on separate pages, or one broken URL.","example":{"code":"missing_meta_description","first_seen_at":"2026-09-02T04:11:09Z","id":311,"kind":"template","label":"Missing meta description","pages":1840,"rank":1,"scope":"Template /shoes/{slug} · 1,840 of 2,010 pages","score":21.4,"severity":"warning","status":"open","template":{"example_url":"https://www.example.com/shoes/trail-runner","id":17,"label":"/shoes/{slug}","pages":2010,"source":"skeleton"},"template_pages":2010}},"FixCheck":{"properties":{"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope","description":"sample or all."},"pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pages","description":"Pages the check reads."},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"checked":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Checked","description":"Pages it could read; null while it runs."},"fixed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fixed","description":"Of those, pages where the issue is gone."},"finished_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Finished At"}},"type":"object","required":["scope","pages","started_at","checked","fixed","finished_at"],"title":"FixCheck","description":"The latest \"Check if fixed\" (started in the dashboard)."},"FixCounts":{"properties":{"status":{"allOf":[{"$ref":"#/components/schemas/StatusTabCounts"}],"description":"Fixes per status tab."},"severity":{"allOf":[{"$ref":"#/components/schemas/SeverityCounts"}],"description":"Fixes of the chosen `status` per severity."}},"type":"object","required":["status","severity"],"title":"FixCounts"},"FixDetail":{"properties":{"fix":{"$ref":"#/components/schemas/Fix"},"issue":{"$ref":"#/components/schemas/FixIssue"},"example_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Example Url","description":"A page to look at first: the template's example or the broken URL."},"history":{"items":{"$ref":"#/components/schemas/FixEvent"},"type":"array","title":"History","description":"The latest 50 events, newest first."}},"type":"object","required":["fix","issue","example_url","history"],"title":"FixDetail","example":{"example_url":"https://www.example.com/shoes/trail-runner","fix":{"code":"missing_meta_description","first_seen_at":"2026-09-02T04:11:09Z","id":311,"kind":"template","label":"Missing meta description","pages":1840,"rank":1,"scope":"Template /shoes/{slug} · 1,840 of 2,010 pages","score":21.4,"severity":"warning","status":"open","template":{"example_url":"https://www.example.com/shoes/trail-runner","id":17,"label":"/shoes/{slug}","pages":2010,"source":"skeleton"},"template_pages":2010},"history":[{"at":"2026-09-02T04:30:00Z","crawl_id":"7d1c0f94-2b8e-4a73-9a10-5f3d8e6c1b02","kind":"opened","pages":1840}],"issue":{"category":"content","code":"missing_meta_description","fix":"Write a meta description of about 150 characters for https://www.example.com/shoes/trail-runner.","help":"The page has no meta description.","label":"Missing meta description","severity":"warning","why":"Search results then show whatever text they pick."}}},"FixEvent":{"properties":{"kind":{"type":"string","title":"Kind","description":"What happened: opened, grew, shrank, resolved, regressed, checked, accepted, wont_fix, snoozed, reopened..."},"pages":{"type":"integer","title":"Pages","description":"Pages affected at that moment."},"at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"At"},"crawl_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crawl Id","description":"The crawl that found it, when a crawl did."},"note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note"}},"type":"object","required":["kind","pages","at","crawl_id","note"],"title":"FixEvent"},"FixIssue":{"properties":{"code":{"type":"string","title":"Code"},"label":{"type":"string","title":"Label"},"severity":{"type":"string","title":"Severity"},"category":{"type":"string","title":"Category"},"help":{"type":"string","title":"Help","description":"What is wrong."},"why":{"type":"string","title":"Why","description":"Why it matters."},"fix":{"type":"string","title":"Fix","description":"How to fix it, with the example page named where the text refers to it."}},"type":"object","required":["code","label","severity","category","help","why","fix"],"title":"FixIssue"},"FixList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Fix"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."},"counts":{"anyOf":[{"$ref":"#/components/schemas/FixCounts"},{"type":"null"}],"description":"Only with `include=count`."}},"type":"object","required":["data","has_more"],"title":"FixList","description":"A site's fixes, best score first (ties by id).","example":{"data":[{"code":"missing_meta_description","first_seen_at":"2026-09-02T04:11:09Z","id":311,"kind":"template","label":"Missing meta description","pages":1840,"rank":1,"scope":"Template /shoes/{slug} · 1,840 of 2,010 pages","score":21.4,"severity":"warning","status":"open","template":{"example_url":"https://www.example.com/shoes/trail-runner","id":17,"label":"/shoes/{slug}","pages":2010,"source":"skeleton"},"template_pages":2010}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"FixPage":{"properties":{"url":{"type":"string","title":"Url"},"page_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Id","description":"The page's id in the site's inventory; null when it is not in it."},"inbound_links":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Inbound Links","description":"Pages linking to an affected page (null for a linking page)."},"anchor_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anchor Text","description":"Link fixes: the broken link's anchor text."},"element_xpath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Element Xpath","description":"Link fixes: the HTML element holding the broken link."}},"type":"object","required":["url","page_id","inbound_links","anchor_text","element_xpath"],"title":"FixPage","description":"A page a fix is about: an affected page, or for a link fix a page that links to the broken URL.","example":{"inbound_links":37,"page_id":48120,"url":"https://www.example.com/shoes/trail-runner"}},"FixPageList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/FixPage"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."},"kind":{"type":"string","title":"Kind","description":"pages: the URLs are affected pages, most linked first. links: the URLs are pages linking to the broken URL (at most 200 are stored, sorted by URL)."}},"type":"object","required":["data","has_more","kind"],"title":"FixPageList","description":"The pages of one fix. `kind` says what each url is.","example":{"data":[{"inbound_links":37,"page_id":48120,"url":"https://www.example.com/shoes/trail-runner"}],"has_more":false,"kind":"pages"}},"FixTemplate":{"properties":{"id":{"type":"integer","title":"Id"},"label":{"type":"string","title":"Label","description":"The URL pattern most of the template's pages share."},"example_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Example Url","description":"One page built from the template."},"pages":{"type":"integer","title":"Pages","description":"Pages built from the template."},"source":{"type":"string","title":"Source","description":"How the pages were grouped: skeleton (page structure) or url (URL pattern)."}},"type":"object","required":["id","label","example_url","pages","source"],"title":"FixTemplate"},"GonePage":{"properties":{"url":{"type":"string","title":"Url"},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code","description":"What the page answers now; null when the crawl did not find it."},"previous_status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Previous Status Code"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Its title in the previous crawl."},"redirect_to":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redirect To","description":"Where it redirects now, when it does; absent when redirects were not counted."}},"type":"object","required":["url"],"title":"GonePage"},"IndexabilityCounts":{"properties":{"indexable":{"type":"integer","title":"Indexable"},"non_indexable":{"type":"integer","title":"Non Indexable"},"unknown":{"type":"integer","title":"Unknown"}},"type":"object","required":["indexable","non_indexable","unknown"],"title":"IndexabilityCounts"},"Inventory":{"properties":{"crawl":{"anyOf":[{"$ref":"#/components/schemas/InventoryCrawl"},{"type":"null"}],"description":"The newest crawl written into the inventory; null before the first crawl."},"coverage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coverage","description":"complete: the crawl covered the site and marked URLs it no longer found as missing. update: it only refreshed what it saw."},"coverage_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Coverage Reason","description":"Why the newest crawl only updated, in words; null when it was complete."},"seo_crawl":{"anyOf":[{"$ref":"#/components/schemas/InventoryCrawl"},{"type":"null"}],"description":"The newest detailed crawl the SEO columns come from."},"sync":{"$ref":"#/components/schemas/InventorySync"},"url_count":{"type":"integer","title":"Url Count","description":"URLs in the inventory, every view together."}},"type":"object","required":["crawl","coverage","coverage_reason","seo_crawl","sync","url_count"],"title":"Inventory","description":"Which crawl the inventory shows and how much of the site it covers: read it before trusting a list.","example":{"coverage":"complete","crawl":{"completed_at":"2026-10-30T03:52:41Z","id":"7d1c0f94-2b8e-4a73-9a10-5f3d8e6c1b02","mode":"full"},"seo_crawl":{"completed_at":"2026-10-30T03:52:41Z","id":"7d1c0f94-2b8e-4a73-9a10-5f3d8e6c1b02","mode":"full"},"sync":{"status":"ok","synced_at":"2026-10-30T03:58:12Z"},"url_count":5120}},"InventoryCrawl":{"properties":{"id":{"type":"string","title":"Id","description":"The crawl's id (a UUID)."},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At","description":"When the crawl finished."},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode","description":"fast or full."},"close_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Close Reason","description":"Why it ended, when not because it finished its work."}},"type":"object","required":["id","completed_at","mode","close_reason"],"title":"InventoryCrawl"},"InventorySync":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"ok, running or failed: whether the inventory is being written or the write failed."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"A short reason when status is failed."},"synced_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Synced At","description":"When the inventory was last written."}},"type":"object","required":["status","error","synced_at"],"title":"InventorySync"},"Issue":{"properties":{"id":{"type":"string","title":"Id","description":"Stable within the crawl: `broken:<row>`, `seo:<page row>:<code>` or `ai:<page row>:<code>`."},"category":{"type":"string","title":"Category","description":"`broken`, `seo` or `ai_readiness`."},"code":{"type":"string","title":"Code","description":"The catalog code, for example `broken_link`, `missing_title`, `js_shell`. Unknown codes may appear."},"label":{"type":"string","title":"Label","description":"The catalog's name for the code."},"severity":{"type":"string","title":"Severity","description":"`error`, `warning` or `info`."},"page_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Page Url","description":"The page the issue is on (for a broken link: the page that links to it)."},"target_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Url","description":"Broken links: the URL that does not work."},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code","description":"Broken links: the HTTP status the target answered, null when it did not answer."},"resource_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Type","description":"Broken links: `link`, `image`, `css`, `js`, `video`..."},"occurrences":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Occurrences","description":"Broken links: how many pages link to the target (at least 1)."},"detail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Detail","description":"A short fact about this page's issue, for example `max-snippet:50`."},"element":{"anyOf":[{"$ref":"#/components/schemas/IssueElement"},{"type":"null"}],"description":"The HTML element the issue sits in."},"fix":{"type":"string","title":"Fix","description":"What to do, in a sentence or two."}},"type":"object","required":["id","category","code","label","severity","fix"],"title":"Issue","description":"One issue of a crawl. Broken links and resources are one issue per broken URL (with how many pages link to it);\npage issues are one per page and issue code.","example":{"category":"broken","code":"broken_link","element":{"tag":"a","text":"Read the guide","xpath":"//*[@id=\"content\"]/p[3]/a"},"fix":"On https://shop.example/blog/care-guide the <a> at //*[@id=\"content\"]/p[3]/a points to https://shop.example/old-guide, which returns 404. Point it to the page that replaced it, or remove the link.","id":"broken:48213","label":"Broken link","occurrences":12,"page_url":"https://shop.example/blog/care-guide","resource_type":"link","severity":"error","status_code":404,"target_url":"https://shop.example/old-guide"}},"IssueElement":{"properties":{"xpath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Xpath","description":"Broken links: where the link sits in the page's HTML."},"selector":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selector","description":"Page issues: a CSS selector for the element to look at."},"tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag","description":"The HTML tag of the element."},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text","description":"Broken links: the anchor text (or alt text) of the link."}},"type":"object","title":"IssueElement"},"IssuePage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Issue"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."},"totals":{"anyOf":[{"$ref":"#/components/schemas/IssueTotals"},{"type":"null"}],"description":"First page only (no `cursor`): the crawl's issue totals; null when they are not stored (see `totals_status`) and on later pages."},"totals_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Totals Status","description":"First page only. `ready`; `incomplete` (the SEO count ran out of time: `seo` is null); `pending` (the crawl's data is still being processed, or it is older than the totals: `totals` is null)."}},"type":"object","required":["data","has_more"],"title":"IssuePage","description":"A page of issues, plus on the first page the crawl's totals. A page can hold fewer than `limit` issues while\n`has_more` is true (a filter that matches few issues is searched in bounded steps): keep following `next_cursor`.","example":{"data":[{"category":"broken","code":"broken_link","element":{"tag":"a","text":"Read the guide","xpath":"//*[@id=\"content\"]/p[3]/a"},"fix":"On https://shop.example/blog/care-guide the <a> at //*[@id=\"content\"]/p[3]/a points to https://shop.example/old-guide, which returns 404. Point it to the page that replaced it, or remove the link.","id":"broken:48213","label":"Broken link","occurrences":12,"page_url":"https://shop.example/blog/care-guide","resource_type":"link","severity":"error","status_code":404,"target_url":"https://shop.example/old-guide"}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque","totals":{"ai_readiness":{"by_code":{"js_shell":12,"noindex":8},"total":65},"broken":29,"computed_at":"2026-10-31T09:14:02Z","not_checked":4,"seo":{"by_code":{"missing_og":43,"missing_title":9},"pages":64,"total":265}},"totals_status":"ready"}},"IssueRef":{"properties":{"code":{"type":"string","title":"Code"},"label":{"type":"string","title":"Label","description":"The issue in words."},"severity":{"type":"string","title":"Severity","description":"error, warning or info."},"category":{"type":"string","title":"Category","description":"indexing, content, social, asset, security or links."}},"type":"object","required":["code","label","severity","category"],"title":"IssueRef"},"IssueTotals":{"properties":{"computed_at":{"type":"string","title":"Computed At","description":"When they were counted (UTC)."},"broken":{"type":"integer","title":"Broken","description":"Broken links and resources. URLs the site refused are not counted as broken."},"not_checked":{"type":"integer","title":"Not Checked","description":"URLs the site refused or that did not answer: neither working nor broken."},"seo":{"anyOf":[{"$ref":"#/components/schemas/SeoTotals"},{"type":"null"}],"description":"Null for a fast crawl (no page data), and while `totals_status` is `incomplete`."},"ai_readiness":{"anyOf":[{"$ref":"#/components/schemas/AiReadinessTotals"},{"type":"null"}],"description":"Null for a fast crawl."}},"type":"object","required":["computed_at","broken","not_checked"],"title":"IssueTotals","description":"Counted once, when the crawl's data was processed, never inside a request."},"IssueType":{"properties":{"code":{"type":"string","title":"Code","description":"The stable code. Codes are never renumbered or reused; new ones appear, so ignore codes you do not know."},"label":{"type":"string","title":"Label","description":"The issue in words."},"severity":{"type":"string","title":"Severity","description":"error, warning or info."},"category":{"type":"string","title":"Category","description":"indexing, content, social, asset, security or links."},"help":{"type":"string","title":"Help","description":"What the check looks at."},"why":{"type":"string","title":"Why","description":"Why it matters."},"fix":{"type":"string","title":"Fix","description":"How to fix it."}},"type":"object","required":["code","label","severity","category","help","why","fix"],"title":"IssueType","example":{"category":"content","code":"missing_title","fix":"Give every page a short, unique title.","help":"The page has no <title> element.","label":"Missing title","severity":"error","why":"Search results show the title; without one they guess."}},"KeyInfo":{"properties":{"name":{"type":"string","title":"Name","description":"The name given to the key."},"prefix":{"type":"string","title":"Prefix","description":"The first characters of the key (pbk_xxxxxxxx): enough to recognise it. The secret is never shown."},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","description":"What the key may do: read, crawl (includes read), webhooks."},"daily_credit_cap":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Daily Credit Cap","description":"Credits the crawls this key starts may cost per UTC day. `-1` = the key was made with no cap; `null` = a key made before the REST API existed (the crawls it starts may check at most 500 pages each)."},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At","description":"When the key stops working (ISO 8601 UTC); null = never."},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At","description":"When the key was last used (ISO 8601 UTC, to the minute); null = never."}},"type":"object","required":["name","prefix","scopes","daily_credit_cap","expires_at","last_used_at"],"title":"KeyInfo"},"Link":{"properties":{"id":{"type":"integer","title":"Id","description":"The row's id, ascending in crawl order. Lists are paged by it; never build a cursor from it."},"url":{"type":"string","title":"Url","description":"The URL that was checked."},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code","description":"The HTTP status; null when there was no answer."},"status":{"type":"string","enum":["working","redirect","broken","not_checked"],"title":"Status","description":"working, redirect (3xx), broken, or not_checked (the crawler could not check it: see `block_reason`)."},"is_broken":{"type":"boolean","title":"Is Broken","description":"True when the crawler found it broken."},"block_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Block Reason","description":"Why a not_checked URL was not checked (bot_protection, rate_limited, access_denied, robots_txt...)."},"resource_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resource Type","description":"link, image, css, js, video, iframe, audio, embed or object."},"link_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link Type","description":"internal, external, or out_of_scope (on your host, outside the folder the crawl stayed in)."},"depth":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Depth","description":"Clicks from the start page; null when no crawled page links to it."},"inbound_links":{"type":"integer","title":"Inbound Links","description":"How many pages of the crawl link to it."},"redirect_target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redirect Target","description":"Where a redirect leads."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"The crawler's short note on a failed check."},"response_time_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Response Time Ms","description":"How long the answer took."}},"type":"object","required":["id","url","status_code","status","is_broken","block_reason","resource_type","link_type","depth","inbound_links","redirect_target","error","response_time_ms"],"title":"Link","description":"One URL a crawl checked.","example":{"depth":2,"id":48213,"inbound_links":14,"is_broken":true,"link_type":"internal","resource_type":"link","response_time_ms":182.4,"status":"broken","status_code":404,"url":"https://www.example.com/old-guide"}},"LinkInfo":{"properties":{"kind":{"type":"string","title":"Kind","description":"a (hyperlink), img, css, js, iframe, media, canonical, hreflang, next or prev; a kind added later reads as `other`."},"kind_label":{"type":"string","title":"Kind Label"},"position":{"type":"string","title":"Position","description":"content, navigation, header, footer or aside; a position added later reads as `other`."},"position_label":{"type":"string","title":"Position Label"},"path_type":{"type":"string","title":"Path Type","description":"How the address was written: absolute, root_relative, protocol_relative or path_relative."},"path_type_label":{"type":"string","title":"Path Type Label"},"anchor_kind":{"type":"string","title":"Anchor Kind","description":"Where the anchor text came from: text, image_alt, title or none."},"anchor_kind_label":{"type":"string","title":"Anchor Kind Label"},"rel":{"items":{"type":"string"},"type":"array","title":"Rel","description":"nofollow, sponsored and ugc, when the link carries them."},"follow":{"type":"string","title":"Follow","description":"follow, or nofollow when the rel says so."},"target_blank":{"type":"boolean","title":"Target Blank"},"scope":{"type":"string","title":"Scope","description":"internal or external."}},"type":"object","required":["kind","kind_label","position","position_label","path_type","path_type_label","anchor_kind","anchor_kind_label","rel","follow","target_blank","scope"],"title":"LinkInfo","description":"What one link is, decoded from the flags the crawl stored (only while the link graph is on)."},"LinkPage":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Link"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."},"total":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total","description":"How many URLs match the filters; only with `include=count`, otherwise null."}},"type":"object","required":["data","has_more"],"title":"LinkPage","description":"A page of checked URLs; `total` is set only with `?include=count`.","example":{"data":[{"depth":2,"id":48213,"inbound_links":14,"is_broken":true,"link_type":"internal","resource_type":"link","response_time_ms":182.4,"status":"broken","status_code":404,"url":"https://www.example.com/old-guide"}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"LinkingPage":{"properties":{"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url","description":"The page that links to this URL."},"anchor_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Anchor Text","description":"The link's anchor text (an image's alt text)."},"element_xpath":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Element Xpath","description":"Where in the page the link sits: the HTML element to edit."},"link":{"anyOf":[{"$ref":"#/components/schemas/LinkInfo"},{"type":"null"}],"description":"What the first link from that page is. Present only while the link graph is switched on for the platform; null = not measured."}},"type":"object","required":["source_url","anchor_text","element_xpath"],"title":"LinkingPage"},"LinkingPages":{"properties":{"total":{"type":"integer","title":"Total","description":"Pages that link here, as the newest crawl counted them (can exceed what is stored)."},"stored_max":{"type":"integer","title":"Stored Max","description":"The most linking pages a crawl stores per URL, whatever the list shows."},"limit":{"type":"integer","title":"Limit","description":"The most this answer lists. The list is capped; it has no cursor."},"items":{"items":{"$ref":"#/components/schemas/LinkingPage"},"type":"array","title":"Items","description":"Sorted by the linking page's URL."}},"type":"object","required":["total","stored_max","limit","items"],"title":"LinkingPages"},"Me":{"properties":{"api_version":{"type":"string","title":"Api Version","description":"The API's major version."},"workspace":{"$ref":"#/components/schemas/WorkspaceInfo"},"role":{"type":"string","title":"Role","description":"The key creator's role in the workspace today: owner, admin, member or viewer."},"plan":{"$ref":"#/components/schemas/PlanInfo"},"credits":{"$ref":"#/components/schemas/CreditsInfo"},"key":{"$ref":"#/components/schemas/KeyInfo"},"api":{"$ref":"#/components/schemas/ApiFlags"}},"type":"object","required":["api_version","workspace","role","plan","credits","key","api"],"title":"Me","example":{"api":{"crawl_enabled":true,"webhooks_v2":false},"api_version":"v1","credits":{"bonus":0,"costs":{"scan_detailed":2,"scan_detailed_owned":1,"scan_fast":1,"scan_fast_owned":0.5,"scan_js_rendering":4,"scan_js_rendering_owned":2},"limit":10000,"period":"2026-10","remaining":8759.5,"unlimited":false,"used":1240.5},"key":{"daily_credit_cap":2000,"expires_at":"2027-01-15T09:00:00Z","last_used_at":"2026-10-31T08:41:00Z","name":"CI","prefix":"pbk_k3x9a7bq","scopes":["read","crawl"]},"plan":{"display_name":"Business","has_export":true,"name":"business","team_seats":10},"role":"owner","workspace":{"id":12,"name":"Acme's workspace"}}},"PageChange":{"properties":{"url":{"type":"string","title":"Url"},"changes":{"additionalProperties":{"$ref":"#/components/schemas/FieldChange"},"type":"object","title":"Changes","description":"By field: status_code, title, meta_description, is_indexable, canonical_url."}},"type":"object","required":["url","changes"],"title":"PageChange"},"PageRef":{"properties":{"url":{"type":"string","title":"Url"},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"}},"type":"object","required":["url"],"title":"PageRef"},"PlanInfo":{"properties":{"name":{"type":"string","title":"Name","description":"The plan's stable name (free, starter, business, business_plus, enterprise...)."},"display_name":{"type":"string","title":"Display Name","description":"The plan's name as the dashboard shows it."},"has_export":{"type":"boolean","title":"Has Export","description":"True when CSV, Excel and PDF exports (and live feeds) are included."},"team_seats":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Team Seats","description":"Team members besides the owner: 0 = owner only, null = unlimited."}},"type":"object","required":["name","display_name","has_export","team_seats"],"title":"PlanInfo"},"SeoTotals":{"properties":{"pages":{"type":"integer","title":"Pages","description":"Pages the SEO checks read."},"total":{"type":"integer","title":"Total","description":"Page issues found, one per page and code."},"by_code":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Code","description":"Pages per issue code (only codes that were found)."}},"type":"object","required":["pages","total","by_code"],"title":"SeoTotals"},"SeverityCounts":{"properties":{"error":{"type":"integer","title":"Error"},"warning":{"type":"integer","title":"Warning"},"info":{"type":"integer","title":"Info"}},"type":"object","required":["error","warning","info"],"title":"SeverityCounts"},"Site":{"properties":{"id":{"type":"integer","title":"Id","description":"The site's id (64-bit integer): pass it as `site_id`."},"url":{"type":"string","title":"Url","description":"The address the site was added with."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"The name given to the site, if any."},"host":{"type":"string","title":"Host","description":"The site's host without www.: www and the bare domain are one site."},"crawl_profile":{"type":"string","title":"Crawl Profile","description":"standard, or allowlisted: PerfBee asked the site's owner to let our crawler in and crawls it fast."},"verified":{"type":"boolean","title":"Verified","description":"True when your workspace proved it controls the host (Settings > My Sites)."},"owned_rate":{"type":"boolean","title":"Owned Rate","description":"True when crawls of this site are billed at the half owned-site rate (verified or allowlisted)."},"fast_lane":{"type":"boolean","title":"Fast Lane","description":"True when the owner's self-serve fast lane is on for this verified host."},"last_crawl":{"anyOf":[{"$ref":"#/components/schemas/CrawlSummary"},{"type":"null"}],"description":"The newest crawl of this site, whatever its status; null before the first."},"schedule":{"anyOf":[{"$ref":"#/components/schemas/SiteSchedule"},{"type":"null"}],"description":"The site's next scheduled crawl; null when none is active."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the site was added."}},"type":"object","required":["id","url","name","host","crawl_profile","verified","owned_rate","fast_lane","last_crawl","schedule","created_at"],"title":"Site","example":{"crawl_profile":"standard","created_at":"2026-09-12T10:21:00Z","fast_lane":false,"host":"example.com","id":7,"last_crawl":{"broken_count":12,"completed_at":"2026-10-30T02:14:51Z","id":"5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","mode":"full","pages_checked":1840,"report_url":"https://dashboard.perfbee.com/#/brokenLinks?scan=5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","started_at":"2026-10-30T02:00:04Z","status":"completed","url":"https://www.example.com/"},"name":"Example shop","owned_rate":true,"schedule":{"day":4,"frequency":"weekly","hour":2,"minute":0,"mode":"full","next_run_at":"2026-11-06T02:00:00Z","timezone":"Europe/Berlin","timezone_offset_minutes":0},"url":"https://www.example.com/","verified":true}},"SiteList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/Site"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."}},"type":"object","required":["data","has_more"],"title":"SiteList","description":"A page of sites.","example":{"data":[{"crawl_profile":"standard","created_at":"2026-09-12T10:21:00Z","fast_lane":false,"host":"example.com","id":7,"last_crawl":{"broken_count":12,"completed_at":"2026-10-30T02:14:51Z","id":"5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","mode":"full","pages_checked":1840,"report_url":"https://dashboard.perfbee.com/#/brokenLinks?scan=5b0a5e4c-2f1e-4b8e-9c47-1d3f6a7b8c90","started_at":"2026-10-30T02:00:04Z","status":"completed","url":"https://www.example.com/"},"name":"Example shop","owned_rate":true,"schedule":{"day":4,"frequency":"weekly","hour":2,"minute":0,"mode":"full","next_run_at":"2026-11-06T02:00:00Z","timezone":"Europe/Berlin","timezone_offset_minutes":0},"url":"https://www.example.com/","verified":true}],"has_more":true,"next_cursor":"eyJ2IjoxfQ.opaque"}},"SitePage":{"properties":{"id":{"type":"integer","title":"Id","description":"The page's id inside the site (a 64-bit integer: store it as one)."},"url":{"type":"string","title":"Url","description":"The URL exactly as the crawl stored it."},"url_type":{"type":"string","title":"Url Type","description":"page, document, other, image, css, js, font, video, iframe, audio or embed."},"link_scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link Scope","description":"internal, outside_folder (same host, outside the folder of a sub-path site) or external."},"status_class":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Class","description":"ok, redirect, broken, gone (HTTP 410), not_checked (the crawler was refused, see `block_reason`) or unknown."},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code","description":"The HTTP status the crawl got; null when there was none."},"block_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Block Reason","description":"Why a URL was not checked (bot wall, robots.txt...); set only with status_class not_checked."},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message","description":"The connection error, when the request failed before an HTTP status."},"redirect_target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Redirect Target","description":"Where a redirect points."},"content_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Type","description":"The response's Content-Type."},"response_time_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Response Time Ms","description":"How long the response took, in milliseconds."},"found_on_page":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Found On Page","description":"A page that links here (the first one the crawl met)."},"found_via":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Found Via","description":"link, sitemap or list: how the crawl first reached it."},"inbound_links":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Inbound Links","description":"How many pages link here; null when the crawl did not cover the whole site."},"in_sitemap":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"In Sitemap","description":"Listed in the sitemap; null when the sitemap was not read in full."},"crawl_depth":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Crawl Depth","description":"Clicks from the start page."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"The page title; the SEO columns are filled only by a detailed crawl."},"meta_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meta Description","description":"The meta description."},"h1":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"H1","description":"The first H1."},"word_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Word Count","description":"Words in the main text."},"title_pixel_width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Title Pixel Width","description":"Estimated width of the title in a search result, in pixels."},"meta_description_pixel_width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Meta Description Pixel Width","description":"Estimated width of the meta description, in pixels."},"canonical_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Canonical Url","description":"The canonical URL the page names."},"meta_robots":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meta Robots","description":"The robots meta directives."},"indexability":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Indexability","description":"indexable, non_indexable or unknown; null for anything but a page."},"indexability_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Indexability Reason","description":"Why: noindex, canonicalised, a status class, robots_txt, not_checked or needs_detailed_scan."},"issues":{"items":{"type":"string"},"type":"array","title":"Issues","description":"The issue codes the page carries, most severe first. Look them up in `GET /issue-types`; ignore codes you do not know."},"seo_crawl_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seo Crawl Id","description":"The detailed crawl the SEO columns and issues come from."},"marked_resolved_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marked Resolved At","description":"When someone marked the URL resolved in the dashboard."},"marked_resolved_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marked Resolved Note","description":"The note left with that mark."},"rechecked_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Rechecked At","description":"When the URL was last rechecked on its own."},"first_seen_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Seen At","description":"When a crawl first saw the URL (ISO 8601 UTC)."},"last_seen_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Seen At","description":"When a crawl last saw it."},"missing_since":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Missing Since","description":"Set when a later complete crawl no longer found the URL."},"previous_status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Previous Status Code","description":"The status before the latest change."},"status_changed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status Changed At","description":"When the status last changed."},"outlinks":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Outlinks","description":"Links on the page. Present only while the link graph is switched on for the platform; null = not measured."},"unique_outlinks":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Unique Outlinks","description":"Distinct link targets on the page. Present only while the link graph is switched on for the platform; null = not measured."},"external_outlinks":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"External Outlinks","description":"Links to other sites. Present only while the link graph is switched on for the platform; null = not measured."},"nofollow_inlinks":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Nofollow Inlinks","description":"Inlinks that carry rel=nofollow. Present only while the link graph is switched on for the platform; null = not measured."},"content_inlinks":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Content Inlinks","description":"Inlinks from the main content, not menus or footers. Present only while the link graph is switched on for the platform; null = not measured."},"link_score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Link Score","description":"PerfBee Link Score, 1 to 100. Present only while the link graph is switched on for the platform; null = not measured."}},"type":"object","required":["id","url","url_type","link_scope","status_class","status_code","block_reason","error_message","redirect_target","content_type","response_time_ms","found_on_page","found_via","inbound_links","in_sitemap","crawl_depth","title","meta_description","h1","word_count","title_pixel_width","meta_description_pixel_width","canonical_url","meta_robots","indexability","indexability_reason","issues","seo_crawl_id","marked_resolved_at","marked_resolved_note","rechecked_at","first_seen_at","last_seen_at","missing_since","previous_status_code","status_changed_at"],"title":"SitePage","description":"One row of the site's page inventory (Site Pages in the dashboard): a URL, what the newest crawl saw there, and\nwhat it found wrong.","example":{"canonical_url":"https://www.example.com/shoes/trail-runner","content_type":"text/html; charset=utf-8","crawl_depth":2,"first_seen_at":"2026-09-02T04:11:09Z","found_on_page":"https://www.example.com/shoes","found_via":"link","h1":"Trail Runner","id":48120,"in_sitemap":true,"inbound_links":37,"indexability":"indexable","issues":["missing_meta_description"],"last_seen_at":"2026-10-30T03:52:41Z","link_scope":"internal","response_time_ms":412,"seo_crawl_id":"0b6f1d52-8a41-4f0e-9d7b-3c5e21a7f9aa","status_class":"ok","status_code":200,"title":"Trail Runner | Example Shoes","title_pixel_width":392,"url":"https://www.example.com/shoes/trail-runner","url_type":"page","word_count":214}},"SitePageCounts":{"properties":{"views":{"allOf":[{"$ref":"#/components/schemas/ViewCounts"}],"description":"Every view over the whole site, whatever the filters."},"in_view":{"type":"integer","title":"In View","description":"Rows in the chosen view after `prefix` and `q`, before the other filters."},"matched":{"type":"integer","title":"Matched","description":"Rows the list holds: the view with every filter applied."},"status":{"allOf":[{"$ref":"#/components/schemas/StatusCounts"}],"description":"`in_view` split by status class."},"indexability":{"allOf":[{"$ref":"#/components/schemas/IndexabilityCounts"}],"description":"`in_view` split by indexability."},"issues":{"additionalProperties":{"type":"integer"},"type":"object","title":"Issues","description":"`in_view` rows carrying each issue code (codes with none are left out)."},"change":{"$ref":"#/components/schemas/ChangeCounts"},"resolved":{"type":"integer","title":"Resolved","description":"Rows in `in_view` that someone marked resolved."}},"type":"object","required":["views","in_view","matched","status","indexability","issues","change","resolved"],"title":"SitePageCounts","description":"What `?include=count` adds: the counts behind the dashboard's chips, one query.","example":{"change":{"changed":3,"new":14},"in_view":3912,"indexability":{"indexable":3402,"non_indexable":301,"unknown":209},"issues":{"missing_meta_description":212,"missing_title":9},"matched":212,"resolved":5,"status":{"broken":31,"gone":2,"not_checked":12,"ok":3801,"redirect":64,"unknown":2},"views":{"links_out":96,"missing":8,"pages":3912,"resources":1104}}},"SitePageDetail":{"properties":{"page":{"$ref":"#/components/schemas/SitePage"},"crawl_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Crawl Id","description":"The newest crawl that saw this URL."},"issue_details":{"items":{"$ref":"#/components/schemas/IssueRef"},"type":"array","title":"Issue Details","description":"`page.issues` decoded with the catalog, same order."},"linking_pages":{"$ref":"#/components/schemas/LinkingPages"}},"type":"object","required":["page","crawl_id","issue_details","linking_pages"],"title":"SitePageDetail","description":"One page, the issues on it in words, and the pages that link to it.","example":{"crawl_id":"7d1c0f94-2b8e-4a73-9a10-5f3d8e6c1b02","issue_details":[{"category":"content","code":"missing_meta_description","label":"Missing meta description","severity":"warning"}],"linking_pages":{"items":[{"anchor_text":"Trail Runner","element_xpath":"/html/body/main/ul/li[3]/a","source_url":"https://www.example.com/shoes"}],"limit":50,"stored_max":200,"total":37},"page":{"canonical_url":"https://www.example.com/shoes/trail-runner","content_type":"text/html; charset=utf-8","crawl_depth":2,"first_seen_at":"2026-09-02T04:11:09Z","found_on_page":"https://www.example.com/shoes","found_via":"link","h1":"Trail Runner","id":48120,"in_sitemap":true,"inbound_links":37,"indexability":"indexable","issues":["missing_meta_description"],"last_seen_at":"2026-10-30T03:52:41Z","link_scope":"internal","response_time_ms":412,"seo_crawl_id":"0b6f1d52-8a41-4f0e-9d7b-3c5e21a7f9aa","status_class":"ok","status_code":200,"title":"Trail Runner | Example Shoes","title_pixel_width":392,"url":"https://www.example.com/shoes/trail-runner","url_type":"page","word_count":214}}},"SitePageList":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SitePage"},"type":"array","title":"Data","description":"The items of this page, in the endpoint's fixed order."},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor","description":"Pass as `cursor` to get the next page; null on the last page."},"has_more":{"type":"boolean","title":"Has More","description":"True when another page follows."},"inventory":{"$ref":"#/components/schemas/Inventory"},"counts":{"anyOf":[{"$ref":"#/components/schemas/SitePageCounts"},{"type":"null"}],"description":"Only with `include=count`."}},"type":"object","required":["data","has_more","inventory"],"title":"SitePageList","description":"A page of the site's inventory, sorted by URL (the only order; for other orders download an export).","example":{"data":[{"canonical_url":"https://www.example.com/shoes/trail-runner","content_type":"text/html; charset=utf-8","crawl_depth":2,"first_seen_at":"2026-09-02T04:11:09Z","found_on_page":"https://www.example.com/shoes","found_via":"link","h1":"Trail Runner","id":48120,"in_sitemap":true,"inbound_links":37,"indexability":"indexable","issues":["missing_meta_description"],"last_seen_at":"2026-10-30T03:52:41Z","link_scope":"internal","response_time_ms":412,"seo_crawl_id":"0b6f1d52-8a41-4f0e-9d7b-3c5e21a7f9aa","status_class":"ok","status_code":200,"title":"Trail Runner | Example Shoes","title_pixel_width":392,"url":"https://www.example.com/shoes/trail-runner","url_type":"page","word_count":214}],"has_more":true,"inventory":{"coverage":"complete","crawl":{"completed_at":"2026-10-30T03:52:41Z","id":"7d1c0f94-2b8e-4a73-9a10-5f3d8e6c1b02","mode":"full"},"seo_crawl":{"completed_at":"2026-10-30T03:52:41Z","id":"7d1c0f94-2b8e-4a73-9a10-5f3d8e6c1b02","mode":"full"},"sync":{"status":"ok","synced_at":"2026-10-30T03:58:12Z"},"url_count":5120},"next_cursor":"eyJ2IjoxfQ.opaque"}},"SiteSchedule":{"properties":{"frequency":{"type":"string","title":"Frequency","description":"daily, weekly or monthly."},"mode":{"type":"string","title":"Mode","description":"fast or full: the mode the scheduled crawl runs in."},"next_run_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Run At","description":"When it runs next; null while it is paused."},"hour":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Hour","description":"Hour of the day it runs, 0 to 23, in the schedule's own time zone."},"minute":{"type":"integer","title":"Minute","description":"Minute of the hour, 0 to 59."},"day":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Day","description":"Day of the week (0 to 6) for weekly, of the month (1 to 31) for monthly."},"timezone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timezone","description":"IANA time zone of hour and day; null = a fixed offset."},"timezone_offset_minutes":{"type":"integer","title":"Timezone Offset Minutes","description":"The fixed offset from UTC in minutes, used when `timezone` is null."}},"type":"object","required":["frequency","mode","next_run_at","hour","minute","day","timezone","timezone_offset_minutes"],"title":"SiteSchedule","description":"The site's next scheduled crawl."},"StartCrawlRequest":{"properties":{"site_id":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Site Id","description":"A site of your workspace (My Sites): its id from the sites list."},"url":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Url","description":"A site in My Sites, as an http:// or https:// URL. A URL with a path inside a registered site crawls that folder only. A URL that is not in My Sites is refused: add the site in PerfBee first."},"mode":{"type":"string","enum":["fast","full"],"title":"Mode","description":"`fast`: links only, the cheapest. `full`: links plus SEO data, structured data and AI readiness for every page (more credits per page).","default":"fast"},"max_pages":{"type":"integer","maximum":10000.0,"minimum":1.0,"title":"Max Pages","description":"Pages to check at most, 1 to 10,000. A key made without a daily credit cap (before the REST API) may ask for at most 500. The most the crawl can cost is max_pages times the page rate, and that must fit the workspace's credits and the key's daily credit cap.","default":100},"render_js":{"type":"boolean","title":"Render Js","description":"Render pages that need JavaScript (smart rendering): rendered pages cost more.","default":false},"preset_id":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Preset Id","description":"A scan preset (a PerfBee preset or one of your workspace's): its checks, exclusions, depth and rules apply. `mode`, `max_pages` and `render_js` always come from this request."}},"additionalProperties":false,"type":"object","title":"StartCrawlRequest","description":"What to crawl and how far. Give exactly one of `site_id` and `url`.","example":{"max_pages":500,"mode":"fast","render_js":false,"site_id":12}},"StatusCounts":{"properties":{"ok":{"type":"integer","title":"Ok"},"redirect":{"type":"integer","title":"Redirect"},"broken":{"type":"integer","title":"Broken"},"gone":{"type":"integer","title":"Gone"},"not_checked":{"type":"integer","title":"Not Checked"},"unknown":{"type":"integer","title":"Unknown"}},"type":"object","required":["ok","redirect","broken","gone","not_checked","unknown"],"title":"StatusCounts"},"StatusTabCounts":{"properties":{"open":{"type":"integer","title":"Open"},"set_aside":{"type":"integer","title":"Set Aside","description":"Accepted, won't-fix or snoozed."},"resolved":{"type":"integer","title":"Resolved"}},"type":"object","required":["open","set_aside","resolved"],"title":"StatusTabCounts"},"ViewCounts":{"properties":{"pages":{"type":"integer","title":"Pages","description":"HTML pages of the site."},"resources":{"type":"integer","title":"Resources","description":"Images, scripts, stylesheets, fonts, media and the site's own files."},"links_out":{"type":"integer","title":"Links Out","description":"Pages and files outside the site or its folder that the site links to."},"missing":{"type":"integer","title":"Missing","description":"URLs a later complete crawl no longer found."}},"type":"object","required":["pages","resources","links_out","missing"],"title":"ViewCounts"},"WebhookDelivery":{"properties":{"id":{"type":"integer","title":"Id","description":"The delivery's id (one event sent to one endpoint, with its retries)."},"event":{"type":"string","title":"Event","description":"The event, or `test` for a test delivery."},"event_id":{"type":"string","title":"Event Id","description":"The event's id, the same as `id` in the payload and in `PerfBee-Event-Id`; it stays the same on every attempt and every redelivery."},"status":{"type":"string","enum":["pending","retrying","delivered","failed"],"title":"Status","description":"pending (waiting for its first attempt), retrying, delivered or failed."},"attempt":{"type":"integer","title":"Attempt","description":"The number of the attempt made last (0 before the first)."},"max_attempts":{"type":"integer","title":"Max Attempts","description":"How many attempts a delivery gets."},"http_status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Http Status","description":"The receiver's HTTP status on the last attempt; null when it did not answer."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Why the last attempt failed when there was no usable answer: a short sentence."},"duration_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Ms","description":"How long the last attempt took."},"next_attempt_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Attempt At","description":"While retrying: when the next attempt is due (ISO 8601 UTC)."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the event was queued for this endpoint (ISO 8601 UTC)."},"payload":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Payload","description":"The body sent, kept until the delivery is delivered; a failed delivery keeps it for 3 days. null otherwise."}},"type":"object","required":["id","event","event_id","status","attempt","max_attempts","http_status","error","duration_ms","next_attempt_at","created_at","payload"],"title":"WebhookDelivery","example":{"attempt":5,"created_at":"2026-11-01T09:30:12Z","duration_ms":412,"event":"scan_data_ready","event_id":"evt_5f0c2b7e9a1d4c3e8b6a7d9f01234567","http_status":503,"id":4182,"max_attempts":5,"payload":{"api_version":"v1","data":{"crawl_id":"0f7c9a52-3d4b-4a39-8c0e-5e2a9d1b6f10","mode":"full","site_id":7},"event":"scan_data_ready","event_description":"Crawl data ready","id":"evt_5f0c2b7e9a1d4c3e8b6a7d9f01234567","timestamp":"2026-11-01T09:30:12.512Z"},"status":"failed"}},"WebhookEndpoint":{"properties":{"id":{"type":"integer","title":"Id","description":"The endpoint's id."},"url":{"type":"string","title":"Url","description":"Where deliveries are POSTed (https, a public address)."},"events":{"items":{"type":"string"},"type":"array","title":"Events","description":"The events it takes: names from GET /webhook-events."},"enabled":{"type":"boolean","title":"Enabled","description":"False while the endpoint is paused: no event is sent to it."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Your note about the endpoint."},"source":{"type":"string","enum":["dashboard","api","migrated"],"title":"Source","description":"Where it was made: the dashboard, this API, or moved from the single endpoint the dashboard had before."},"signed":{"type":"boolean","title":"Signed","description":"True when deliveries carry a PerfBee-Signature. An endpoint moved from before without a secret is unsigned until you rotate one."},"previous_secret_valid_until":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous Secret Valid Until","description":"While a rotation overlaps: when the old secret stops signing (ISO 8601 UTC); otherwise null."},"legacy_secret_header_until":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Legacy Secret Header Until","description":"Only on an endpoint moved from before: when the old plain `X-PerfBee-Secret` header stops (ISO 8601 UTC); otherwise null."},"last_delivery_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Delivery At","description":"When the last attempt was made (ISO 8601 UTC); null before the first."},"last_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Status","description":"The last delivery's state: delivered, retrying or failed."},"consecutive_failures":{"type":"integer","title":"Consecutive Failures","description":"Failed attempts in a row; a delivered event ends the run."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the endpoint was made (ISO 8601 UTC)."}},"type":"object","required":["id","url","events","enabled","description","source","signed","previous_secret_valid_until","legacy_secret_header_until","last_delivery_at","last_status","consecutive_failures","created_at"],"title":"WebhookEndpoint","example":{"consecutive_failures":0,"created_at":"2026-10-20T14:02:00Z","description":"CI gate","enabled":true,"events":["scan_data_ready","scan_failed"],"id":3,"last_delivery_at":"2026-11-01T09:30:12Z","last_status":"delivered","signed":true,"source":"api","url":"https://hooks.example.com/perfbee"}},"WebhookEndpointCreate":{"properties":{"url":{"type":"string","maxLength":512,"title":"Url","description":"An https:// address on a public host, without credentials. It is checked again at every delivery."},"events":{"items":{"type":"string"},"type":"array","maxItems":40,"minItems":1,"title":"Events","description":"The events to send: names from GET /webhook-events."},"description":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Description","description":"A note for yourself."}},"additionalProperties":false,"type":"object","required":["url","events"],"title":"WebhookEndpointCreate","example":{"description":"CI gate","events":["scan_data_ready","scan_failed"],"url":"https://hooks.example.com/perfbee"}},"WebhookEndpointSecret":{"properties":{"id":{"type":"integer","title":"Id","description":"The endpoint's id."},"url":{"type":"string","title":"Url","description":"Where deliveries are POSTed (https, a public address)."},"events":{"items":{"type":"string"},"type":"array","title":"Events","description":"The events it takes: names from GET /webhook-events."},"enabled":{"type":"boolean","title":"Enabled","description":"False while the endpoint is paused: no event is sent to it."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Your note about the endpoint."},"source":{"type":"string","enum":["dashboard","api","migrated"],"title":"Source","description":"Where it was made: the dashboard, this API, or moved from the single endpoint the dashboard had before."},"signed":{"type":"boolean","title":"Signed","description":"True when deliveries carry a PerfBee-Signature. An endpoint moved from before without a secret is unsigned until you rotate one."},"previous_secret_valid_until":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Previous Secret Valid Until","description":"While a rotation overlaps: when the old secret stops signing (ISO 8601 UTC); otherwise null."},"legacy_secret_header_until":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Legacy Secret Header Until","description":"Only on an endpoint moved from before: when the old plain `X-PerfBee-Secret` header stops (ISO 8601 UTC); otherwise null."},"last_delivery_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Delivery At","description":"When the last attempt was made (ISO 8601 UTC); null before the first."},"last_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Status","description":"The last delivery's state: delivered, retrying or failed."},"consecutive_failures":{"type":"integer","title":"Consecutive Failures","description":"Failed attempts in a row; a delivered event ends the run."},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At","description":"When the endpoint was made (ISO 8601 UTC)."},"secret":{"type":"string","title":"Secret","description":"The signing secret (`whsec_...`). Shown ONCE, here: store it now, it cannot be read again."}},"type":"object","required":["id","url","events","enabled","description","source","signed","previous_secret_valid_until","legacy_secret_header_until","last_delivery_at","last_status","consecutive_failures","created_at","secret"],"title":"WebhookEndpointSecret","description":"An endpoint and its signing secret: the only answers that carry one are the creation and the rotation.","example":{"consecutive_failures":0,"created_at":"2026-10-20T14:02:00Z","description":"CI gate","enabled":true,"events":["scan_data_ready","scan_failed"],"id":3,"last_delivery_at":"2026-11-01T09:30:12Z","last_status":"delivered","secret":"whsec_p3Qx1kT0n8a5ZyV2mL7cR4dB9wUeHsJfGiNoAqXtYbc","signed":true,"source":"api","url":"https://hooks.example.com/perfbee"}},"WebhookEndpointUpdate":{"properties":{"url":{"anyOf":[{"type":"string","maxLength":512},{"type":"null"}],"title":"Url","description":"A new address; the endpoint's delivery history starts again."},"events":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":40,"minItems":1},{"type":"null"}],"title":"Events","description":"The new list of events."},"enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Enabled","description":"false pauses the endpoint, true resumes it."},"description":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Description","description":"A new note, or null to clear it."}},"additionalProperties":false,"type":"object","title":"WebhookEndpointUpdate","description":"Only the fields you send change. `description: null` clears the note.","example":{"enabled":false}},"WebhookEventType":{"properties":{"event":{"type":"string","title":"Event","description":"The event name a webhook endpoint subscribes to."},"group":{"type":"string","title":"Group","description":"The part of the product it belongs to."},"label":{"type":"string","title":"Label","description":"The event in words."},"description":{"type":"string","title":"Description","description":"When it fires."}},"type":"object","required":["event","group","label","description"],"title":"WebhookEventType","example":{"description":"Every finished crawl, with or without broken links.","event":"scan_completed","group":"Site Crawler","label":"Scan completed"}},"WorkspaceInfo":{"properties":{"id":{"type":"integer","title":"Id","description":"The workspace's id (the id of its owner's account)."},"name":{"type":"string","title":"Name","description":"The workspace's name."}},"type":"object","required":["id","name"],"title":"WorkspaceInfo"},"CreditsExtra":{"properties":{"needed":{"description":"Credits the operation needs (worst case).","title":"Needed","type":"number"},"available":{"description":"Credits the workspace has left this month.","title":"Available","type":"number"},"held_by_running_crawls":{"description":"Credits reserved by crawls that are still running.","title":"Held By Running Crawls","type":"number"}},"required":["needed","available","held_by_running_crawls"],"title":"CreditsExtra","type":"object"},"FieldError":{"properties":{"in":{"description":"Where the value was read: body, query, path or header.","title":"In","type":"string"},"field":{"description":"The parameter or body field, dotted for nested ones.","title":"Field","type":"string"},"message":{"description":"Why it was refused. The value that was sent is never echoed.","title":"Message","type":"string"},"type":{"description":"A short machine word for the kind of mistake.","title":"Type","type":"string"}},"required":["in","field","message","type"],"title":"FieldError","type":"object"},"RateLimitExtra":{"properties":{"scope":{"description":"Which limit was hit: key, heavy, start, workspace or network.","title":"Scope","type":"string"},"limit":{"description":"Calls allowed in the window.","title":"Limit","type":"integer"},"window_seconds":{"description":"Length of the window in seconds.","title":"Window Seconds","type":"integer"}},"required":["scope","limit","window_seconds"],"title":"RateLimitExtra","type":"object"},"ProblemDetail":{"additionalProperties":true,"description":"An RFC 9457 problem document. Clients switch on `code`; `detail` is for people and may change.","example":{"code":"not_found","detail":"No crawl with this id in your workspace.","request_id":"7c1f0a52-3d4b-4a39-8c0e-5e2a9d1b6f10","status":404,"title":"Not found","type":"https://perfbee.com/developers/errors#not_found"},"properties":{"type":{"description":"A URL naming the kind of error: https://perfbee.com/developers/errors#<code>.","title":"Type","type":"string"},"title":{"description":"A short, stable summary of the kind of error.","title":"Title","type":"string"},"status":{"description":"The HTTP status, repeated.","title":"Status","type":"integer"},"code":{"description":"The stable machine code (see the error registry in the docs).","title":"Code","type":"string"},"detail":{"description":"What went wrong this time, in a sentence.","title":"Detail","type":"string"},"request_id":{"description":"The request's X-Request-ID: quote it when you contact support.","title":"Request Id","type":"string"},"errors":{"anyOf":[{"items":{"$ref":"#/components/schemas/FieldError"},"type":"array"},{"type":"null"}],"default":null,"description":"422 only: every field that was refused.","title":"Errors"},"credits":{"anyOf":[{"$ref":"#/components/schemas/CreditsExtra"},{"type":"null"}],"default":null,"description":"402 only: the credit arithmetic."},"rate_limit":{"anyOf":[{"$ref":"#/components/schemas/RateLimitExtra"},{"type":"null"}],"default":null,"description":"429 from a rate limit: which one and how big."},"required_scope":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"description":"403 scope_required only: the scope the endpoint needs.","title":"Required Scope"}},"required":["type","title","status","code","detail","request_id"],"title":"ProblemDetail","type":"object"}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"PerfBee API key (pbk_...)","description":"Create a key in the dashboard (Settings > API keys) and send it as `Authorization: Bearer pbk_...`."}},"headers":{"X-RateLimit-Limit":{"description":"Calls allowed in the current one-minute window by the tightest limit that applies.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Calls left in the window under that limit.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time the window ends and the counters start again.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before trying again.","schema":{"type":"integer"}},"WWW-Authenticate":{"description":"Always `Bearer realm=\"perfbee-api\"`.","schema":{"type":"string"}}}},"tags":[{"name":"Account","description":"Who a key acts as, its plan and credits."},{"name":"Crawls","description":"Sites and crawls: read them, their links, AI readiness and exports."},{"name":"Issues","description":"A crawl's issues, the diff against the previous crawl and issue totals."},{"name":"Pages","description":"Site Pages, fixes, the issue catalog and live feeds."},{"name":"Crawl control","description":"Start and cancel a crawl."},{"name":"Webhooks","description":"Signed webhook endpoints and their deliveries."}],"security":[{"BearerAuth":[]}]}