{"openapi":"3.1.0","info":{"title":"fastmon API","summary":"Real-time website performance monitoring.","description":"Fastmon is a real-time website performance monitoring platform: RUM (Real User\nMonitoring), Core Web Vitals, traffic analytics, and rule-based notifications.\n\nThis document is the authoritative reference for the fastmon API. It's\ngenerated from code and updated on every release. Anything not documented here\nis unsupported.\n\n## Base URL\n\n    https://api.fastmon.eu\n\nRequests to the historical `/v1` prefix (`https://api.fastmon.eu/v1/...`)\nkeep working: the prefix is stripped server-side and the request is served\nby the same endpoint. New integrations should use the unprefixed paths.\n\n## Authentication\n\nAll API endpoints require an authenticated principal via a **Bearer\ntoken**:\n\n    Authorization: Bearer fm_...\n\nGenerate a token from the fastmon dashboard (Account → API Token). Tokens\nare hashed server-side; only the prefix is queryable. Lost tokens\ncannot be recovered; regenerate instead.\n\nThe two public ingest endpoints (`POST /c/{collector_hash}` and\n`GET /s/{source_hash}.js`) are unauthenticated and authorize requests via\nthe per-site hash embedded in the URL.\n\n## Response shape\n\n* **Single resource**: returned raw: `{ \"id\": \"...\", \"name\": \"...\", ... }`\n* **List**: wrapped: `{ \"data\": [...], \"meta\": { \"limit\": 50, \"offset\": 0, \"total\": 242, \"has_more\": true } }`\n* **Error**: wrapped: `{ \"error\": { \"code\": \"...\", \"message\": \"...\", \"request_id\": \"...\", \"details\": {...} } }`\n\nSee §1–§2 of `API_STANDARDS.md` for the full envelope spec.\n\n## IDs and timestamps\n\n* Resource IDs are **UUID v7** strings. Generated server-side via `uuid.uuid7()`.\n* Timestamps are **ISO 8601 UTC with `Z` suffix**: `2026-04-18T12:34:56.123456Z`.\n\n## Pagination\n\n* Default `limit=50`, max `100` on every list endpoint.\n* Most list endpoints use offset pagination: `?limit=50&offset=50`; responses\n  include `meta.total` and `meta.has_more`.\n* High-volume endpoints (notably analytics sessions and events) use **cursor**\n  pagination instead: responses carry `meta.next_cursor`, which the client\n  sends back as `?cursor=<token>` to fetch the next page. These responses do\n  not include `meta.total`.\n* Which scheme applies is visible from the response `meta` shape: check for\n  `next_cursor` (cursor) vs `offset`+`total` (offset).\n\n## Request correlation\n\nEvery response carries `X-Request-ID`. If a client sends one, the server\npropagates it; otherwise the server generates a UUID v7. The same ID is\nmirrored into `error.request_id` on failures; always include it when\nreporting issues.\n\n## Public ingest endpoints\n\n`POST /c/{collector_hash}` (beacon ingestion) and `GET /s/{source_hash}.js`\n(tracking script) are **not** part of the dashboard API and are exempt from\nthese standards. They have their own wire contract documented in\n`API_STANDARDS.md` §22.\n\n## Status\n\nThe API is actively developed.","contact":{"name":"fastmon","url":"https://fastmon.eu/","email":"support@fastmon.eu"},"version":"2026.9.16"},"paths":{"/c/{collector_hash}":{"get":{"tags":["collector"],"summary":"Collect Pixel","description":"Collect beacon via 1x1 pixel (GET).\n\nThis is the third fallback in the tracker's delivery chain, after\nsendBeacon (unload paths) and fetch keepalive POST (live paths). It\nfires when fetch() rejects, which most commonly happens when the\nrenderer is torn down between an OPTIONS preflight response and the\nPOST going out. Since v1.4.2 the live fetch path uses Content-Type\ntext/plain and no custom headers, so it never preflights and this\nfallback should be rare; we still accept it for ad-blocker-bypass\ncontexts and ancient browsers without fetch.\n\nIdentity (pvid/ver/lifecycle) is forwarded so the row collapses against\nany successfully-delivered POST for the same pageview via\nReplacingMergeTree(version).","operationId":"collect_pixel_c__collector_hash__get","parameters":[{"name":"collector_hash","in":"path","required":true,"schema":{"type":"string","title":"Collector Hash"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations":{"get":{"tags":["organizations"],"summary":"List Organizations","description":"List organizations the caller has access to (direct or via partner).\n\nAn API key sees only the organizations it was issued for, not every one its\nowner belongs to. Without that cut the reach restriction would still hold on\nevery other route but leak the tenant list here, which is exactly the thing\na key bound to one customer must not learn about the others.\n\nA credential the organization owns has no memberships to walk at all: its\nreach IS the answer, so it is returned directly rather than derived from a\nperson who does not exist.","operationId":"listOrganizations","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_OrganizationResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["organizations"],"summary":"Create Organization","description":"Create a new organization.\n\nThe user who creates the organization automatically becomes the owner with\nfull permissions. New organizations start PENDING: members can look around,\nbut applications/sites (and thus data ingestion) require review first. Users\nwith the admin-granted `auto_approve_orgs` flag skip the queue — their orgs\nstart APPROVED with source `trusted_user`.","operationId":"createOrganization","security":[{"APIKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}":{"get":{"tags":["organizations"],"summary":"Get Organization","description":"Get organization by ID, including what the caller may do in it.\n\nLoads the org itself rather than taking `OrgDep`: pairing that loader with\nan access alias would run `OrgAccessChecker` twice (two dependency objects,\ntwo identical membership SELECTs).","operationId":"getOrganization","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["organizations"],"summary":"Update Organization","description":"Update organization. Owner-only.\n\n`ai_enabled` is a compliance-grade kill-switch: when flipped off, every\n`/ai/*` endpoint returns 403 and no beacon data from this org\never reaches Mistral. Owner-level access is required so a single\nregular member can't unilaterally enable / disable AI for the whole\norganization.","operationId":"updateOrganization","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["organizations"],"summary":"Delete Organization","description":"Delete organization and all related data. Owner-only.\n\nIrreversibly cascades to sites, invites, partner links and memberships, so\nit requires owner-level access (matching `update`/`transfer-ownership`).\nMember-level access — including partner-org access to a client org — is not\nenough to destroy an organization.\n\n**What gets deleted:**\n- All sites belonging to the organization\n- All pending invites\n- All member associations (memberships)\n- The organization itself\n\n**What is preserved:**\n- User accounts of all members (by default)\n\n**Optional: delete_account**\n\nIf `delete_account=true` is passed as a query parameter, the current user's\naccount will also be deleted after the organization is removed.","operationId":"deleteOrganization","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"delete_account","in":"query","required":false,"schema":{"type":"boolean","description":"If true, also delete the requesting user's account","default":false,"title":"Delete Account"},"description":"If true, also delete the requesting user's account"}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/usage":{"get":{"tags":["organizations"],"summary":"Get Usage","description":"Get beacon usage for the current billing period (calendar month).\n\nPass `?by_site=true` to include per-site breakdown.","operationId":"getOrganizationUsage","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"by_site","in":"query","required":false,"schema":{"type":"boolean","description":"Include per-site breakdown","default":false,"title":"By Site"},"description":"Include per-site breakdown"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/audit-log":{"get":{"tags":["organizations"],"summary":"List Audit Log","description":"Durable trail of relevant changes for this org (consent toggles, site\ndeletion, hash rotation, ...), newest first. Owner-only.","operationId":"listOrganizationAuditLog","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"action","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/AuditAction"},{"type":"null"}],"description":"Filter by action","title":"Action"},"description":"Filter by action"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_AuditLogEntry_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/members":{"get":{"tags":["organizations","members"],"summary":"List Members","description":"List organization members.\n\nReturns all members with their roles (owner/member).","operationId":"listOrganizationMembers","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_MemberResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["organizations"],"summary":"Add Member","description":"Add a user to the organization. User must already exist.\n\nRequires *direct* membership: this seats a member with no invite handshake,\nso partner-via-partner access must not be able to inject members into a\nmanaged client org (it would route members in without their consent). A\npartner seats real users through the invite flow instead.","operationId":"addOrganizationMember","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberAdd"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/transfer-ownership":{"post":{"tags":["organizations","members"],"summary":"Transfer Ownership","description":"Transfer ownership of the organization to another member.\n\n**Permissions:**\n- Requires `org:transfer` (an owner)\n- Target user must be an existing member of the organization\n\n**Process:**\n- The caller becomes a regular member, the target becomes an owner\n- A swap of exactly these two seats: organizations may hold SEVERAL\n  owners (seated via add_member, invites or role promotion), and any\n  other owner keeps their seat. This route exists for the common\n  single-owner handoff, it does not enforce owner uniqueness.\n\n**Request Body:**\n- `new_owner_user_id`: UUID of the member who will become the new owner","operationId":"transferOrganizationOwnership","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnershipTransferRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/invites":{"get":{"tags":["organizations"],"summary":"List Invites","description":"List pending invites.","operationId":"listOrganizationInvites","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_InviteResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["organizations"],"summary":"Create Invite","description":"Create an organization invite and send email.\n\n**Request Body:**\n- `email`: Email address to invite\n- `role`: Role to assign (default: \"member\"). Inviting an \"owner\" requires\n  the caller to be an owner of the org - or an owner of a partner org that\n  manages it (the partner→customer ownership handoff). Otherwise a regular\n  member could invite a second account as owner and escalate. \"viewer\" and\n  \"member\" need no extra authority: neither grants more than the inviter\n  already holds.\n\nSends an invitation email with a unique token that expires in 7 days.","operationId":"createOrganizationInvite","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/members/{member_id}":{"patch":{"tags":["members"],"summary":"Update Member Role","description":"Change a member's role.\n\nThe only way to move someone between viewer / member / owner after they\njoined. Two rules beyond the `member:manage` gate, both of which a role\nbundle cannot express:\n\n- **Granting OWNER** goes through the same check as an owner invite\n  (`_can_grant_owner_role`), so a partner org cannot mint owners in a\n  client org it merely manages.\n- **The last owner cannot be demoted.** An org without an owner has nobody\n  who can change settings, invite, or delete it - and `accept_invite`\n  already treats owner-less orgs as a defect it silently repairs. Refuse\n  here rather than create the state.","operationId":"updateOrganizationMemberRole","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"member_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Member Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberRoleUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["members"],"summary":"Remove Member","description":"Remove a member from the organization or leave the organization.\n\n**Permissions:**\n- Only owners can remove other members\n- Any member can leave the organization (remove themselves)\n\n**Use cases:**\n- Remove another member from your organization (owner only)\n- Leave an organization yourself (when the membership's user_id matches your own)\n\n**Behavior when multiple members exist:**\n- Only the specified member's association is removed\n- Organization, sites, and invites remain intact\n\n**Behavior when this is the LAST member:**\n- All sites are deleted\n- All pending invites are deleted\n- The organization itself is deleted\n- The user account is preserved (NOT deleted)","operationId":"removeOrganizationMember","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"member_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Member Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/api-keys":{"get":{"tags":["org-keys"],"summary":"List Org Keys","description":"The org's keys - display metadata only, the secret is never returned.\n\nSame shape as the personal key list; filter client-side is unnecessary\nbecause only `kind='org'` keys bound to this org appear here.\n\nEach entry carries `editable`, which answers \"may I change this one\" for the\ncaller - false for a key holding more than they do. The dashboard would\notherwise have to rebuild that rule from the scopes and the caller's\npermissions, and one rule in two repositories drifts. Revoking is not gated\nby it and needs no flag: whoever sees this list may pull anything on it.","operationId":"listOrgApiKeys","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"include_revoked","in":"query","required":false,"schema":{"type":"boolean","description":"Also return revoked keys. Off by default so the list keeps meaning 'what can authenticate right now'.","default":false,"title":"Include Revoked"},"description":"Also return revoked keys. Off by default so the list keeps meaning 'what can authenticate right now'."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ApiKeyInfo_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["org-keys"],"summary":"Create Org Key","description":"Mint an org key. The secret is shown exactly once.\n\nBound to this org by construction, and capped at what the person minting it\nholds here - the same rule as a personal key, applied to a different owner.\nThe one thing it can never carry is `org_key:manage`: a key that can mint\nkeys would hand its holder a second one without the session and the step-up\nthe first one cost.\n\nNothing else is subtracted. An owner may give an org key owner-grade scopes,\nbecause that is a decision an owner is allowed to make - and the alternative,\na hidden member-level cap, meant a key that quietly did less than the dialog\nsaid. The audit entry names the acting human as actor; the key itself\nbecomes the actor only later, on the requests it makes.","operationId":"createOrgApiKey","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgKeyCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/api-keys/{key_id}":{"patch":{"tags":["org-keys"],"summary":"Update Org Key","description":"Rename an org key, change what it may do, or both. The secret is\nuntouched.\n\nOpen only to someone who holds what the key holds: an owner-grade key is not\neditable by a member, not downwards and not even to rename it. Revoking it\nstays open to them, which is the move that matters when a key is suspected.\nThe reasoning is in `_require_authority_over`.\n\nWithin that, step-up is asked only when the edit gives the key MORE than it\nhad - a scope it did not carry, or a later expiry. Both are re-granting\nauthority and are a mint in all but name. Narrowing and renaming pass\nwithout a factor. The ceiling for a widening is what the person editing\nholds today, never what the original minter held.","operationId":"updateOrgApiKey","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgKeyUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyInfo"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["org-keys"],"summary":"Revoke Org Key","description":"Revoke an org key. It stops authenticating immediately; no other key is\naffected. No step-up, matching the personal revoke route: revocation is the\nfail-safe direction, and a password prompt during a leak is a cost paid at\nexactly the wrong time.\n\n**No `_require_authority_over` here, and that is the whole point of the\nrule** rather than an omission: a member may not reshape an owner-grade key,\nbut must always be able to kill one. Containment cannot depend on an owner\nbeing awake. Anyone who may see the list may pull anything on it.","operationId":"revokeOrgApiKey","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/api-keys/{key_id}/rotate":{"post":{"tags":["org-keys"],"summary":"Rotate Org Key","description":"Issue a successor with the same name, scopes and org, and retire this\none. The new secret is shown exactly once.\n\nMint conditions apply, because whoever rotates walks away with a working\nsecret: the scopes are re-checked against what this person holds today, so a\nkey cannot outlive its creator's authority by being rotated. That is the\nsame precondition editing carries, and it is now literally the same call.","operationId":"rotateOrgApiKey","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyRotate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/connections":{"get":{"tags":["connections"],"summary":"List Connections","description":"The apps connected to this organization, newest first.\n\nOrg-owned only. A member's personal connection is theirs to list and to end\n(`GET /account/connections`); it cannot outlive them and cannot exceed their\nrole, so it is not something this list would give the organization control\nover - see the module docstring.","operationId":"listOrgConnections","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"include_revoked","in":"query","required":false,"schema":{"type":"boolean","description":"Also return disconnected apps. Off by default so the list keeps meaning 'what can act for this organization right now'.","default":false,"title":"Include Revoked"},"description":"Also return disconnected apps. Off by default so the list keeps meaning 'what can act for this organization right now'."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ConnectionInfo_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/connections/{grant_id}":{"delete":{"tags":["connections"],"summary":"Revoke Connection","description":"Disconnect an app.\n\nSpends every refresh token under the grant at once, so the app cannot rotate\nits way back in and has to go through consent again. Access tokens already\nissued are not hunted down - they expire on their own within minutes, which\nis the price of not keeping a revocation list and the reason that lifetime\nis short.\n\nNo step-up, like every other revoke here: revocation is the fail-safe\ndirection, and a password prompt is a cost paid at exactly the wrong moment.\nSession-only, because ending the credentials an incident response depends on\nmust not itself be doable with a credential.","operationId":"revokeOrgConnection","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"grant_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Grant Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/sites":{"get":{"tags":["sites"],"summary":"List Sites","description":"List all sites for an organization. Filter by tag(s) (AND semantics) and/or\nby `application_id` (the app's domains).","operationId":"listSites","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"tag","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Tag"}},{"name":"application_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Filter to the domains (sites) of one application","title":"Application Id"},"description":"Filter to the domains (sites) of one application"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SiteResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["sites"],"summary":"Create Site","description":"Create a site (a domain) under an existing application. The embed + all\ncollection config live on the application (`application_id`, required); only\nthe domain, name, tags and the optional per-domain overrides are set here. To\ncreate a standalone site, create its application first (POST /applications),\nthen add the domain here.","operationId":"createSite","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/sites/status":{"get":{"tags":["sites"],"summary":"Get Org Sites Status","description":"Beacon status for every site in the org in one call.\n\nOrg-scoped twin of `get_site_status` (same per-site fields), so the\ndashboard header widget can render all sites without N status calls. One\nClickHouse aggregate grouped by `site_id`; sites with no beacons still\nappear with zeroed counts. Ordering follows the site list (id/creation\norder from the SELECT). Membership is enforced by `OrgSiteRead`.","operationId":"getOrgSitesStatus","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OrgSiteStatusItem"},"title":"Response Getorgsitesstatus"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/tags":{"get":{"tags":["sites"],"summary":"List Tags","description":"List all unique tags in use across the organization's sites.","operationId":"listSiteTags","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Response Listsitetags"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}":{"get":{"tags":["sites"],"summary":"Get Site","description":"Get site by ID.","operationId":"getSite","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["sites"],"summary":"Update Site","description":"Update a site's own (per-domain) fields. Collection config + hashes live on\nthe Application (one baked bundle per app) and are edited there, not per Site.","operationId":"updateSite","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sites"],"summary":"Delete Site","description":"Delete site. If it was the sole domain of its application, the application\n(and its releases) is removed too; a shared application is kept for its\nsiblings.","operationId":"deleteSite","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/status":{"get":{"tags":["sites"],"summary":"Get Site Status","description":"Get site beacon status: today's count, current rate, and last beacon timestamp.","operationId":"getSiteStatus","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteStatusResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/applications":{"get":{"tags":["applications"],"summary":"List Applications","description":"List the organization's applications, each with its domain (site) count.","operationId":"listApplications","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ApplicationResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["applications"],"summary":"Create Application","description":"Provision an application: one embed whose collection config applies to every\ndomain it runs on, with the concrete Site for each beacon resolved at ingest by\nthe page-URL host. Sites are added by adopting/assigning domains (or\nauto-provision).","operationId":"createApplication","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/applications/unknown-hostnames":{"get":{"tags":["applications"],"summary":"List Unknown Hostnames","description":"Hostnames observed hitting an application that matched no registered site\n— candidates to adopt as new sites, each tagged with the application that\nobserved it. Backed by a best-effort Valkey counter (7-day TTL); empty if\nValkey is unavailable.","operationId":"listApplicationUnknownHostnames","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnknownHostnamesResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/applications/unknown-hostnames/{hostname}":{"delete":{"tags":["applications"],"summary":"Dismiss Unknown Hostname","description":"Dismiss a discovered hostname (after adopting it, or to hide noise).\n\nRemoves it for EVERY application that observed it — once the domain is a Site\n(or the customer hid it) it's no longer a suggestion regardless of source.","operationId":"dismissApplicationUnknownHostname","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"hostname","in":"path","required":true,"schema":{"type":"string","maxLength":255,"title":"Hostname"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}":{"get":{"tags":["applications"],"summary":"Get Application","operationId":"getApplication","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["applications"],"summary":"Update Application","description":"Update an application. Config changes re-render the served bundle (cache\ninvalidated).","operationId":"updateApplication","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["applications"],"summary":"Delete Application","description":"Delete an application and all its sites (their beacon data included — the\nembed is gone, so the domains can no longer collect). The embed stops\nresolving immediately.","operationId":"deleteApplication","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}/rotate-hashes":{"post":{"tags":["applications"],"summary":"Rotate Application Hashes","description":"Rotate the application's script and collector hashes. Existing embeds stop\nworking until the snippet is updated everywhere!","operationId":"rotateApplicationHashes","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}/proxy-secret":{"post":{"tags":["applications"],"summary":"Rotate Application Proxy Secret","description":"Generate the application's proxy-trust secret, or rotate it if one exists.\n\nThe secret authorizes a customer-run beacon proxy (via the FM-Proxy-Key\nheader) to forward the real visitor IP in X-Forwarded-For. On rotation the\nold secret stays valid as `proxy_secret_previous` until the next rotation,\nso proxy configs can be updated without losing geo/session quality. The\nedge picks the change up within its sync interval, not instantly.","operationId":"rotateApplicationProxySecret","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["applications"],"summary":"Disable Application Proxy Secret","description":"Disable proxy trust: invalidate both the current and the previous secret.\n\nBeacons from the customer's proxy keep flowing afterwards; the edge just\nfalls back to the proxy server's IP as the client IP (the pre-feature\nbehavior). Idempotent: deleting an absent secret is a no-op.","operationId":"disableApplicationProxySecret","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}/sites":{"get":{"tags":["applications"],"summary":"List Application Sites","description":"List the domains (sites) this application runs on.","operationId":"listApplicationSites","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SiteResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["applications"],"summary":"Create Application Site","description":"Adopt a domain into the application as a member site. The site is a pure\ndomain/analytics unit — it carries no hashes/config of its own; the\napplication's config applies at ingest, so only the domain is needed.\nTypically fed a hostname from the discovery list; on success that hostname is\ncleared from the list.","operationId":"createApplicationSite","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationSiteCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}/sites/{site_id}":{"put":{"tags":["applications"],"summary":"Assign Application Site","description":"Move an existing site into this application. The application claims the\ndomain for ingest + releases. Re-assigning to the same application is a no-op.\n\nThe site's previous application is left in place even if it ends up with no\nsites — an empty application keeps its embed/config and can take on new\ndomains later; deleting it is an explicit action (DELETE /applications/{id}).","operationId":"assignApplicationSite","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SiteResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}/detect-pagetype":{"post":{"tags":["applications"],"summary":"Detect Application Pagetype","description":"Find out which shop system this application runs, by reading its home page.\n\nAnswers the question the `pagetype_ruleset` setting asks, without making\nanybody open DevTools and read `document.body.className`. The probe target is\nthe application's own domain, never a URL from the caller: this endpoint makes\nthe server fetch a page, so the only address it ever visits is one the\ncustomer registered here.\n\nDetection only. The result is not written, because a probe reads one page of\none domain while the setting governs every page of the application.","operationId":"detectApplicationPageType","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageTypeDetectionResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}/pagetype/discover":{"post":{"tags":["applications"],"summary":"Discover Application Pagetype Rules","description":"Propose `pagetype_rules` from a few pages the customer labelled.\n\nThe customer says \"this URL is a product page\". scout reads it, and the\nclass that appears there and on nothing else is the proposal. The home page\nis read alongside as the contrast, because a single page cannot say which of\nits thirty classes means \"product\".\n\nProposals only. The response carries a `rules` list shaped exactly like the\nfield, and somebody PATCHes it after looking.","operationId":"discoverApplicationPageTypeRules","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageTypeDiscoverRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageTypeDiscoverResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/releases":{"get":{"tags":["releases"],"summary":"List Org Releases","description":"List all releases across an organization, newest first. Optionally restrict\nto one application.","operationId":"listOrgReleases","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"application_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional: restrict to one application","title":"Application Id"},"description":"Optional: restrict to one application"},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"To"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ReleaseResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/applications/{app_id}/releases":{"get":{"tags":["releases"],"summary":"List Application Releases","description":"List an application's releases, newest first.","operationId":"listApplicationReleases","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"To"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ReleaseResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["releases"],"summary":"Create Application Release","description":"Create a release on an application (a one-site app = that site; a multi-site\napp = a coordinated marker across all its domains).","operationId":"createApplicationRelease","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"app_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"App Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/releases":{"get":{"tags":["releases"],"summary":"List Releases","description":"List releases for a site (its application's releases).","operationId":"listReleases","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"From"}},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"To"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_ReleaseResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["releases"],"summary":"Create Release","description":"Create a release for a site (on its application).","operationId":"createRelease","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/releases/{release_id}":{"get":{"tags":["releases"],"summary":"Get Release","description":"Get a single release by ID.","operationId":"getRelease","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Release Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["releases"],"summary":"Update Release","description":"Update a release.","operationId":"updateRelease","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Release Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReleaseResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["releases"],"summary":"Delete Release","description":"Delete a release.","operationId":"deleteRelease","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Release Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/analytics/beacons":{"post":{"tags":["analytics"],"summary":"Query Beacons Records","description":"Row-level drill-down: return individual beacons matching the filter.\n\nPaired with `/analytics/query` (which aggregates). A dashboard click on an\naggregate row sends the same filters here to get the specific beacons behind\nit. No metric aggregation: raw column values only, projected through the\n`fields` whitelist.\n\nBeyond the shared `filters`, two scopes are specific to this endpoint because\nthey read columns the aggregate rollups do not carry: `error_fingerprint`\n(Nested) and `server_timing` (Map), e.g. `{\"pop\": [\"DE-1331\"]}` for one CDN\nPoP or `{\"elasticsearch\": []}` for every pageview that reported that key.\n\nResponse is uncached (rows change every ingest). Total-count is fetched in\nthe same round-trip via asyncio.gather so the UI knows whether pagination\nis worth showing.","operationId":"queryAnalyticsBeacons","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BeaconsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BeaconsResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/beacon-breakdowns":{"post":{"tags":["analytics"],"summary":"Query Beacon Breakdowns","description":"Get the orthogonal beacon-ingestion breakdowns: privacy class,\ndelivery channel, lifecycle stage, and tracker bundle version. See\n`BeaconBreakdownsResponse` for the semantics of each dimension.","operationId":"queryAnalyticsBeaconBreakdowns","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BeaconBreakdownsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BeaconBreakdownsResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/resource-breakdown":{"post":{"tags":["analytics"],"summary":"Query Resource Breakdown","description":"Get resource breakdown by type (script, css, img, font, other).","operationId":"queryAnalyticsResourceBreakdown","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceBreakdownRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceBreakdownResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/third-party":{"post":{"tags":["analytics"],"summary":"Query Third Party","description":"Top third-party domains by request count.\n\nPer-domain blocking duration is not available here; if you need a duration\nproxy, query `/analytics/query` with the `dominant_third_party_category`\ndimension.","operationId":"queryAnalyticsThirdParty","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThirdPartyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThirdPartyResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/server-timing":{"post":{"tags":["analytics"],"summary":"Query Server Timing","description":"Server-Timing dashboard panel: four blocks.\n\n- `cache`: cdn / origin cache-status distribution (count per status).\n- `cache_age`: p50/p75/p95 of the cache age per layer, in SECONDS (the\n  phases are milliseconds), plus the `content` layer = cdn + origin under a\n  CDN hit, which is the age of what the visitor actually saw.\n- `phases`: p50/p75/p95 of the eight backend-phase durations (NULLs\n  skipped), plus `count` = pageviews reporting the phase, so a percentile\n  over 12 pageviews is distinguishable from one over 50k.\n- `top_keys`: custom server-timing keys. Timed keys (`server_timing_dur`)\n  come first, ranked by p75; categorical keys that only ever carried a desc\n  (`server_timing_desc`, e.g. `pop;desc=\"DE-1331\"`) follow with p75_ms=None\n  and their top values. `limit` applies to each group, so the block holds at\n  most 2×limit items.","operationId":"queryAnalyticsServerTiming","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerTimingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerTimingResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/fetch-xhr":{"post":{"tags":["analytics"],"summary":"Query Fetch Xhr","description":"FetchXhr (fetch/XHR) dashboard panel: three blocks.\n\n- `totals`: aggregate calls, errors, and worst-case duration.\n- `endpoints`: per-endpoint aggregates grouped by method/host/path (the\n  `other` rollup bucket is excluded, reflected only in totals), sorted by\n  impact.\n- `outliers`: the slowest individual calls.","operationId":"queryAnalyticsFetchXhr","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FetchXhrRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FetchXhrResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/fetch-xhr/detail":{"post":{"tags":["analytics"],"summary":"Query Fetch Xhr Detail","description":"Host (or endpoint) drill-down — the analogue of `/error-types/detail` (which\nkeys on `fingerprint`). Keyed by `host`; `method`/`path` are optional\nrefinements (omit for the whole host, give `path` for one endpoint).\n\nFour `ARRAY JOIN`s over `beacons FINAL` (cumulative per-pvid state → FINAL),\nsharing one scope filter (`host` [+ method] [+ path]): a summary, the\nper-endpoint list (group by method/path), the per-page breakdown (group by\nthe beacon `url`) and the individual trace calls (`fetch_xhr_outliers`, with\nstatus + the page they ran on). No 037/L1 dependency — `url` lives on the\nsame row as the Nested columns. Status distribution beyond these trace\nsamples needs the Phase-2 per-endpoint status counters.","operationId":"queryAnalyticsFetchXhrDetail","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FetchXhrDetailRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FetchXhrDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/loaf":{"post":{"tags":["analytics"],"summary":"Query Loaf","description":"Get Long Animation Frames (LoAF) data.\n\nTwo-part query:\n- Summary (`total_frames`, `avg_duration`) is sourced from the cheap\n  `loaf_count` / `loaf_total_duration` Phase-3 columns.\n- Per-script breakdown (`data`) ARRAY JOINs the `loaf` Nested.","operationId":"queryAnalyticsLoAF","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoAFRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoAFResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/funnels/checkout":{"post":{"tags":["analytics"],"summary":"Query Checkout Funnel","description":"The cart -> checkout -> success funnel and its series - observed facts only.\n\nEach visitor is counted once per step they reached at least once, in the\nbucket of their funnel ENTRY. The window totals are therefore exactly the\ncolumn sums of the series, which is why one query answers both.","operationId":"queryAnalyticsCheckoutFunnel","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutFunnelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutFunnelResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/funnels/checkout/journeys":{"post":{"tags":["analytics"],"summary":"Query Checkout Journeys","description":"The pageview journeys of the visitors who hit one funnel stage.\n\nTwo steps, because the second one has to be bounded by the first: pick the\nmost recent `limit` visitors that hit the stage inside the window, then\nread their pageviews back out of the same table (`full_journey=True`) or\njust the matching ones (`False`).\n\nThe read-back window is widened by +-24h so a journey that straddles the\nwindow edge comes back whole. It cannot need more than that: the stitch's\nsalt rotates daily, so no row older or newer than that belongs to the same\nvisitor anyway.","operationId":"queryAnalyticsCheckoutJourneys","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutJourneysRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutJourneysResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/element-targets":{"post":{"tags":["analytics"],"summary":"Query Element Targets","description":"Rank the attributed elements (CSS selector paths) for lcp / cls / inp.","operationId":"queryAnalyticsElementTargets","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ElementTargetsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ElementTargetsResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/error-types":{"post":{"tags":["analytics"],"summary":"Query Error Types","description":"Get breakdown of error signatures from collected beacons.\n\nReads the structured `errors` Nested column. Each beacon stores up to 5\n(type, count, sample_message, frame_hosts, frame_lines, frame_cols,\nfingerprint, is_first_party) entries; we ARRAY JOIN and aggregate by\n`fingerprint`, the canonical server-computed signature key.\n\nDisplay projections (error_type, sample_message, frames) are aggregated\nvia `any()` since within a fingerprint group they're stable by\nconstruction (the fingerprint hashes those exact inputs); using `any()`\nrather than `argMax/groupArray` keeps the query cheap.","operationId":"queryAnalyticsErrorTypes","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorTypesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorTypesResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/error-types/detail":{"post":{"tags":["analytics"],"summary":"Query Error Detail","description":"Drill-down for a single error signature, keyed by `fingerprint`.\n\nReturns summary stats, a time series, top-N breakdowns across the requested\ndimensions, and recent sample beacons, all in one request.","operationId":"queryAnalyticsErrorDetail","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDetailRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/error-types/symbolicate":{"post":{"tags":["analytics"],"summary":"Query Error Symbolication","description":"Resolve the stack frames of one error signature to a code location.\n\nSeparate from `/error-types/detail` on purpose. It leaves the process to\nfetch the customer's bundle, so it is slower than every other analytics\nread and it fails in ways the drill-down must survive. The dashboard asks\nfor it after the detail has rendered, and a frame that cannot be resolved\ncomes back with a status rather than an error.","operationId":"queryAnalyticsErrorSymbolication","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSymbolicationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorSymbolicationResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/experience-score":{"post":{"tags":["analytics"],"summary":"Query Experience Score","description":"Compute experience scores per visitor segment.\n\nReturns letter grades (A+ through F) and numeric scores (0.0–10.0)\nfor Desktop, Mobile, Slow Connections, and All Visitors.","operationId":"queryAnalyticsExperienceScore","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperienceScoreRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperienceScoreResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/failed-resources":{"post":{"tags":["analytics"],"summary":"Query Failed Resources","description":"Resources that failed to load, grouped by host and path.\n\nReads the same `errors` Nested column the error list reads, restricted to\n`ResourceLoadError`. That type carries exactly one frame, whose host and\npath are the failing resource itself, so the group-by keys come straight\noff `frame_hosts[1]` / `frame_paths[1]` with no extra column.\n\nThe HOST is always there; the path is not. Stack frames are opt-in per site\n(`collect_error_frames`, off by default) and without them the privacy strip\nkeeps a path only when the frame host is EXACTLY the page host. The bucket\nasks the registrable domain instead, so a resource on the shop's own CDN\nsubdomain lands in `first_party` and still arrives host-only. That gap is a\nprivacy classification (`docs/data_collection.md` §3.9) and not something\nthis endpoint decides.\n\n`pageviews` counts distinct `pvid`, which is duplicate-invariant and so\nsurvives both the ARRAY JOIN row explosion and a pageview that sent several\nbeacons. `count` does NOT: this reads `beacons` rather than `beacons FINAL`,\nso inside the un-merged window a pageview that sent three beacons counts\nits errors three times. Deliberate and consistent with the error-types\npanel next to it, which reads the same way; the MCP tool reads FINAL and so\nreports a smaller total for the same period. See `aggregates.error_totals`,\nwhich documents the identical divergence.","operationId":"queryAnalyticsFailedResources","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FailedResourcesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FailedResourcesResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/failed-resources/detail":{"post":{"tags":["analytics"],"summary":"Query Failed Resource Detail","description":"Drill-down for a single failed resource, keyed by `fingerprint`.\n\nThe mirror of `/analytics/error-types/detail` for the other population, and\ndeliberately the same shape: summary, time series, top-N breakdowns and\nrecent samples in one request. It is a separate route rather than a mode of\nthe error one because the two differ in the only place that matters, the\ndenominator: a share of the JavaScript `error_count` is meaningless for a\nsignal that migration 073 took out of that count.\n\n`count` reads `beacons` rather than `beacons FINAL`, so inside the un-merged\nwindow a pageview that sent several beacons counts its failures several\ntimes. `pageviews` counts distinct `pvid` and is duplicate-invariant.\nIdentical to the list endpoint next to it, on purpose.","operationId":"queryAnalyticsFailedResourceDetail","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FailedResourceDetailRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FailedResourceDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/histogram":{"post":{"tags":["analytics"],"summary":"Query Histogram","description":"Get histogram distribution for a metric.\n\n**Metrics:** lcp, fcp, cls, inp, ttfb, tbt, dns_lookup, tcp_connection, etc.\n\n**Buckets:** Define boundaries as array, e.g., [0, 500, 1000, 2500, 4000]\ncreates buckets: <0, 0-500, 500-1000, 1000-2500, 2500-4000, 4000+\n\n**Example for LCP histogram:**\n```json\n{\n    \"time_range\": {\"from\": \"2024-01-01\", \"to\": \"2024-01-08\"},\n    \"metric\": \"lcp\",\n    \"buckets\": [0, 500, 1000, 2500, 4000]\n}\n```","operationId":"queryAnalyticsHistogram","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistogramRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistogramResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/query":{"post":{"tags":["analytics"],"summary":"Query Analytics","description":"Execute a flexible analytics query against RUM data.\n\n**Metrics:** lcp, fcp, cls, inp, ttfb, tbt, page_load_time, requests,\n`visitors` (distinct visitors; `identity`=stitch|session picks the backing\nidentifier, stitch preferred), etc.\n\n**Aggregations:** count, avg, p50, p75, p90, p95, p99, min, max, sum\n\n**Grouping:** By time intervals (hour, day, week, month) and/or dimensions\n(browser, device_type, country, etc.)\n\n**Filters:** site_id, browser, device_type, country, url (with wildcards), etc.\n\n**Comparison:** Set compare_to to compare with previous_period, previous_week, or previous_month\n\n**Limits:**\n- Max 90 days time range\n- Max 10 metrics per query\n- Max 2 GROUP BY dimensions\n- Max 10,000 rows per response","operationId":"queryAnalytics","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsQueryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsQueryResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/visitors":{"post":{"tags":["analytics"],"summary":"Query Visitors","description":"List visitors with summary stats, grouped by the resolved `identity`\n(stitch — preferred — or session).\n\nEach row is one visitor: page count, duration, device info, and average\nperformance. Cursor paginated, ordered by (start_time DESC, id DESC).\n\nAggregate browsing only; the per-visitor journey (`/visitors/detail`) is the\nconsent-gated drill-in.","operationId":"listAnalyticsVisitors","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorsListRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CursorPaginatedResponse_VisitorSummaryItem_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/analytics/visitors/detail":{"post":{"tags":["analytics"],"summary":"Query Visitor Detail","description":"Get all page visits for one visitor, ordered chronologically.\n\nReturns individual beacons with URL, timestamp, navigation type, and\nperformance metrics for each page view.\n\nNeeds a per-visitor identifier: `identity=session` or `identity=stitch`\n(whichever the site collects — the caller passes the same identity the\nvisitor list used). A site collecting neither (the `minimal` posture) simply\nhas no visitors to drill into. Any other identity value is rejected with 422.","operationId":"getAnalyticsVisitorDetail","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetailRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisitorDetailResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/synthetic/pages":{"get":{"tags":["synthetic"],"summary":"List Org Synthetic Pages","description":"List monitored pages across all sites of the org (manual first, then auto).\n\nOrg-scoped twin of `list_synthetic_pages`: `SyntheticPage` has no\n`organization_id`, so scope is resolved by joining `sites.organization_id`;\neach row still carries its own `site_id`. Optional `site_id` narrows to one\nsite. `summary=true` attaches the cached latest-result health snapshot per\npage (concurrency-capped), same as the site-scoped list.","operationId":"listOrgSyntheticPages","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Optional: restrict to one site","title":"Site Id"},"description":"Optional: restrict to one site"},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/SyntheticPageSource"},{"type":"null"}],"description":"Filter by manual/auto","title":"Source"},"description":"Filter by manual/auto"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"description":"Substring match on URL","title":"Q"},"description":"Substring match on URL"},{"name":"summary","in":"query","required":false,"schema":{"type":"boolean","description":"Attach the latest-result health summary per page","default":false,"title":"Summary"},"description":"Attach the latest-result health summary per page"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SyntheticPageListItem_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages":{"post":{"tags":["synthetic"],"summary":"Create Synthetic Page","description":"Create a synthetic page (URL normalized + must be under the site domain).\n\nRegistering the CS site always kicks off exactly one immediate analysis — you\ncan't create a CS site without it running once — so even a paused page\n(`schedule=false`) produces this one creation run; its `analysis_uuid` is returned\nso the client polls `analyses/{uuid}/status` instead of firing a redundant `run`.\n\n`mode=monitor` (default) is a sticky, quota-counted page honoring the schedule\nflags. `mode=oneshot` is an unbudgeted \"measure now\": schedules forced off,\n`nocache` forced true, and a missing creation-run id is fatal (502) rather than\ntolerated — the run *is* the deliverable. A one-shot stays viewable via the normal\ndetail/run endpoints and can be promoted later via PATCH (source→manual + schedule).\n\nOne-shot is intentionally **unbounded** (no quota) — note the cost: CS has no\nreliable teardown, so each one-shot on a *new* URL leaves a CS site we can't reap.\nAdd a cap here once CS supports teardown.","operationId":"createSyntheticPage","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticPageCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticPageCreateResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict - Resource already exists or operation not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["synthetic"],"summary":"List Synthetic Pages","description":"List monitored pages (manual first, then auto by rank). Paginated + filterable.\nWith `summary=true`, each row carries its latest-result score/last-run (one\nbackend call per page, cached) — avoids the client doing N result calls.","operationId":"listSyntheticPages","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/SyntheticPageSource"},{"type":"null"}],"description":"Filter by manual/auto","title":"Source"},"description":"Filter by manual/auto"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"description":"Substring match on URL","title":"Q"},"description":"Substring match on URL"},{"name":"summary","in":"query","required":false,"schema":{"type":"boolean","description":"Attach the latest-result health summary per page","default":false,"title":"Summary"},"description":"Attach the latest-result health summary per page"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SyntheticPageListItem_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/summary":{"get":{"tags":["synthetic"],"summary":"Get Synthetic Summary","description":"Site-wide overview: a per-page sparkline (recent per-run scores + run count)\nplus the aggregate latest score across pages and total run count.\n\nBuilt live from the 1h-cached per-page series — no stored aggregate, so CS stays\nthe single source of truth. Concurrency-capped like the list summary.","operationId":"getSyntheticSummary","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticSummaryResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/auto/refresh":{"post":{"tags":["synthetic"],"summary":"Refresh Auto Pages","description":"Populate auto pages from the site's Top-N RUM URLs (additive in v1).","operationId":"refreshSyntheticAutoPages","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SyntheticPageResponse"},"title":"Response Refreshsyntheticautopages"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}":{"patch":{"tags":["synthetic"],"summary":"Update Synthetic Page","description":"Update monitoring config: `schedule`, `ttfb_schedule`, `nocache`.\n\nTurning a schedule off pushes the new schedule state to CS; `schedule=false`\npauses the recurring Lighthouse run (the page stays and is still runnable on\ndemand). Turning it back on restores the recurring run. `nocache` toggles CS\ncache-bypass for the page's future runs (it is persisted and applied on the\nnext trigger; a `nocache`-only change does not itself fire a new CS run).","operationId":"updateSyntheticPage","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticPageUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticPageResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["synthetic"],"summary":"Delete Synthetic Page","description":"Delete a monitored page. Tears down the CS site (stops its schedules) via\nthe provider's delete endpoint; if that call fails the local page is still\nremoved and the CS site is flagged cs_orphan for later reconciliation.","operationId":"deleteSyntheticPage","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/run":{"post":{"tags":["synthetic"],"summary":"Run Synthetic Page","description":"Trigger an on-demand analysis (the run completes asynchronously at CS).\n\nAlways allowed for an existing page — a paused page (`schedule=false`) can still\nbe run on demand; the page's recurring schedules are preserved on the rerun.\nUses the page's `nocache` setting unless the `nocache` query param overrides it\nfor this single run.","operationId":"runSyntheticPage","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"nocache","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Override cache-busting for this run; omit to use the page's `nocache` setting. true = bust the page's CDN cache (fresh origin fetch), false = measure with normal CDN caching.","title":"Nocache"},"description":"Override cache-busting for this run; omit to use the page's `nocache` setting. true = bust the page's CDN cache (fresh origin fetch), false = measure with normal CDN caching."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticRunResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/analyses/{analysis_uuid}/status":{"get":{"tags":["synthetic"],"summary":"Get Synthetic Analysis Status","description":"Progress of an in-flight analysis (for run UX). Not cached — status changes\nwhile the run is in progress.\n\nWhen the run reports done, we drop the page's 1h overview caches (sparkline +\nlatest summary) so the just-finished run shows up immediately — our only\ninvalidation signal, since CS has no completion webhook.","operationId":"getSyntheticAnalysisStatus","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"analysis_uuid","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Analysis Uuid"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticAnalysisStatus"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/results":{"get":{"tags":["synthetic"],"summary":"List Synthetic Results","description":"Fetch synthetic-monitoring result history for a page, shaped to our\nasset-free schema.","operationId":"listSyntheticResults","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"result_type","in":"query","required":false,"schema":{"type":"string","pattern":"^(cs|ttfb|all)$","default":"cs","title":"Result Type"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticResultsResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/runs":{"get":{"tags":["synthetic"],"summary":"List Synthetic Runs","description":"Lightweight run list backing the run-selector: per-run id + timestamp +\nper-device score only — no scores[]/ttfb/curation, so the selector payload stays\nsmall. Fetched live from CS (the system of record); pick a run, then use its\n`analysis_uuid` on the detail endpoints.","operationId":"listSyntheticRuns","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 8601 lower bound","title":"From"},"description":"ISO 8601 lower bound"},{"name":"to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ISO 8601 upper bound","title":"To"},"description":"ISO 8601 upper bound"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyntheticRunsResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/lab-vs-field":{"get":{"tags":["synthetic"],"summary":"Get Lab Vs Field","description":"Compare a CS lab run against RUM field p75, per device. The comparison axis is\nthe lab-measurable CWV (LCP/FCP/CLS/TTFB); INP is field-only (shown beside the lab\nTBT proxy). Also returns the CS lab CommerceScore and our field Experience Score\nside by side. Latest run unless `analysis_uuid` given; field reflects `window_days`.","operationId":"getSyntheticLabVsField","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"window_days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":7,"title":"Window Days"}},{"name":"analysis_uuid","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Target a specific run; default latest","title":"Analysis Uuid"},"description":"Target a specific run; default latest"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabVsFieldResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/ttfb":{"get":{"tags":["synthetic"],"summary":"Get Synthetic Ttfb","description":"Diagnose TTFB: CS server-side phase breakdown vs RUM field p75, classifying\nserver-bound vs network/geo-bound. CS phases are per-page; field p75 per device.\nLatest run unless `analysis_uuid` given.","operationId":"getSyntheticTtfb","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"window_days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":7,"title":"Window Days"}},{"name":"analysis_uuid","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Target a specific run; default latest","title":"Analysis Uuid"},"description":"Target a specific run; default latest"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TtfbDiagnosisResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/timeseries":{"get":{"tags":["synthetic"],"summary":"Get Synthetic Timeseries","description":"Chart series for the device: sparse `lab` points (one per CS Lighthouse run,\nscore + CWV from that run's scores[]) and raw `ttfb` points (one per dedicated\n5-min TTFB run, full DNS→transfer phases) overlaid on the regular `field` p75 line\n(RUM). `lab.ttfb` is Lighthouse's server-only TTFB; the `ttfb` series is the full\nphase breakdown — different measurements, kept in separate series. The `ttfb`\nseries is device-independent (CS measures TTFB once per run).\n\n`series` selects which to compute — only the requested ones are fetched; the rest\nreturn as empty lists.","operationId":"getSyntheticTimeseries","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"device","in":"query","required":false,"schema":{"type":"string","pattern":"^(desktop|mobile)$","default":"desktop","title":"Device"}},{"name":"window_days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Window Days"}},{"name":"interval","in":"query","required":false,"schema":{"type":"string","pattern":"^(hour|day)$","default":"day","title":"Interval"}},{"name":"series","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated subset of lab,ttfb,field to compute. Unrequested series come back empty; use it to skip the expensive TTFB pull when unneeded. An empty/blank value means all series.","default":"lab,ttfb,field","title":"Series"},"description":"Comma-separated subset of lab,ttfb,field to compute. Unrequested series come back empty; use it to skip the expensive TTFB pull when unneeded. An empty/blank value means all series."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimeseriesResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/lighthouse":{"get":{"tags":["synthetic"],"summary":"Get Synthetic Lighthouse","description":"Curated Lighthouse report (latest run unless `analysis_uuid` given): category\nscores, metrics, opportunities, and native LH audit objects for waterfall /\nthird-party /\nresource-summary / filmstrip / main-thread).","operationId":"getSyntheticLighthouse","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"device","in":"query","required":false,"schema":{"type":"string","pattern":"^(desktop|mobile)$","default":"desktop","title":"Device"}},{"name":"analysis_uuid","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Target a specific run; default latest","title":"Analysis Uuid"},"description":"Target a specific run; default latest"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LighthouseReportResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/lighthouse/raw":{"get":{"tags":["synthetic"],"summary":"Get Synthetic Lighthouse Raw","description":"The complete, unshaped Lighthouse report for a run + device (~250KB; latest\nunless `analysis_uuid` given). Use the smaller `/lighthouse` unless you need it.","operationId":"getSyntheticLighthouseRaw","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"device","in":"query","required":false,"schema":{"type":"string","pattern":"^(desktop|mobile)$","default":"desktop","title":"Device"}},{"name":"analysis_uuid","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Target a specific run; default latest","title":"Analysis Uuid"},"description":"Target a specific run; default latest"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Getsyntheticlighthouseraw"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sites/{site_id}/synthetic/pages/{page_id}/lighthouse/summary":{"get":{"tags":["synthetic"],"summary":"Get Stored Lighthouse Summary","description":"Read-only: the stored AI summary for a run (latest unless `analysis_uuid`), or\n**404** if none has been generated yet. NEVER generates — no LLM call, no rate-limit\ncost — so the UI can decide between a \"View\" and a \"Generate\" affordance without\ntriggering (and paying for) generation. Use `POST` to actually generate.\n\nRun resolution is the same domain-guarded, cached path the other Lighthouse routes\nuse (so a foreign `analysis_uuid` can't be read); only the LLM work is skipped.","operationId":"getStoredSyntheticLighthouseSummary","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"device","in":"query","required":false,"schema":{"type":"string","pattern":"^(desktop|mobile)$","default":"desktop","title":"Device"}},{"name":"language","in":"query","required":false,"schema":{"type":"string","pattern":"^(en|de)$","default":"en","title":"Language"}},{"name":"analysis_uuid","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Target a specific run; default latest","title":"Analysis Uuid"},"description":"Target a specific run; default latest"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LighthouseSummaryResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["synthetic"],"summary":"Get Synthetic Lighthouse Summary","description":"An AI summary of a page's Lighthouse run (latest unless `analysis_uuid`).\n\nGenerated once per (run, device): English first, then translated to German, and\n**both stored** in `lighthouse_summaries` — a completed run is immutable, so repeat\nrequests are served from the DB (`cached=true`) at no LLM cost. Requires the org's\nAI to be enabled (`require_ai_enabled`).","operationId":"getSyntheticLighthouseSummary","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"page_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Page Id"}},{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Site Id"}},{"name":"device","in":"query","required":false,"schema":{"type":"string","pattern":"^(desktop|mobile)$","default":"desktop","title":"Device"}},{"name":"language","in":"query","required":false,"schema":{"type":"string","pattern":"^(en|de)$","default":"en","title":"Language"}},{"name":"analysis_uuid","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"description":"Target a specific run; default latest","title":"Analysis Uuid"},"description":"Target a specific run; default latest"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LighthouseSummaryResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/issues":{"get":{"tags":["issues"],"summary":"List Issues","operationId":"listIssues","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/IssueStatus"},{"type":"null"}],"title":"Status"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/IssueCategory"},{"type":"null"}],"title":"Category"}},{"name":"severity","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/IssueSeverity"},{"type":"null"}],"title":"Severity"}},{"name":"application_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Application Id"}},{"name":"site_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id"}},{"name":"include_shadow","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Shadow"}},{"name":"include_stats","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Stats"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_IssueResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/issues/{issue_id}":{"get":{"tags":["issues"],"summary":"Get Issue","operationId":"getIssue","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"issue_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Issue Id"}},{"name":"include_stats","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Stats"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueDetailResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["issues"],"summary":"Update Issue","description":"Triage: resolve, reopen, or mute.\n\nEvery transition writes an `issue_event` with the acting user. That audit\ntrail is not decoration: the plan's precision-feedback loop (§7d) reads mute\nand quick-resolve actions as the false-positive proxy signal used to\nrecalibrate detectors, so losing the actor or the timing loses the metric.","operationId":"updateIssue","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"issue_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Issue Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueResponse"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/issues/{issue_id}/explanation":{"get":{"tags":["issues"],"summary":"Explain Issue","description":"Why this issue exists: the recorded gate protocol plus the diagnosis.\n\nServes the numbers the engine actually decided on (stored per evaluation\nin the evidence), never a re-computation against today's thresholds. The\nsignificance checks carry engine vocabulary and are filtered out unless\nan admin asks with `include_stats`; members still see every gate's\nverdict and the human-unit checks (samples, percentage points).","operationId":"explainIssue","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"issue_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Issue Id"}},{"name":"include_stats","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Stats"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueExplanationResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/issues/{issue_id}/comment":{"post":{"tags":["issues"],"summary":"Comment Issue","operationId":"createIssueComment","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"issue_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Issue Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueComment"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueEventResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/highlights":{"get":{"tags":["highlights"],"summary":"List Highlights","operationId":"listHighlights","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"application_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Application Id"}},{"name":"include_shadow","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Shadow"}},{"name":"include_stats","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Stats"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_HighlightResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/notifications/metadata":{"get":{"tags":["notifications"],"summary":"List notification rule inputs","description":"List every metric, aggregation, dimension and allowed window size that\na notification rule can reference. Drives the metric picker and the window\ndropdown in the rule editor UI.","operationId":"getNotificationMetadata","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetadataResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/notifications/presets":{"get":{"tags":["notifications"],"summary":"List rule templates","description":"Return the set of ready-made rule templates (LCP regression, error\nspike, traffic drop, etc.). Used as the starting point in the new-rule\nflow: the client pre-fills the editor from the chosen preset and the\nuser only fills in scope + recipients.","operationId":"listNotificationPresets","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PresetResponse"},"title":"Response Listnotificationpresets"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/notifications/rules":{"get":{"tags":["notifications"],"summary":"List notification rules","description":"List every notification rule in the organization, with their configured\nactions nested. Action secrets (webhook HMAC key, Slack / Discord URLs)\nare masked in the response; users rotate them by re-entering new values\non edit.","operationId":"listNotificationRules","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_RuleResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["notifications"],"summary":"Create a notification rule","description":"Create a new rule together with its actions in a single call. The\nscope target (site or tag) is validated against the org. Requires org\nowner role.","operationId":"createNotificationRule","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/organizations/{org_id}/notifications/preview":{"post":{"tags":["notifications"],"summary":"Historical preview of a rule shape","description":"Replay a rule shape (which may or may not be saved yet) against the\nlast N days of data and return time-series buckets with threshold\nbreaches + the exact number of notifications the state machine would\nhave emitted.\n\nPowers the chart in the rule editor: as the user tweaks metric,\naggregation, threshold, window, filters or the re-notify cadence, the\nclient re-calls this endpoint and re-renders the chart. Bucket size is\nalways equal to the rule's evaluation window so each bucket's value\nrepresents one real evaluation.","operationId":"previewNotificationRule","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BacktestRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BacktestResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/notification-rules/{rule_id}":{"get":{"tags":["notifications"],"summary":"Get a rule","description":"Fetch a single rule by ID, with its actions. Action secrets are\nmasked on read; see `List notification rules`.","operationId":"getNotificationRule","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["notifications"],"summary":"Update a rule","description":"Update mutable fields on an existing rule (name, threshold, window,\noperator, filters, re-notify cadence, enabled state). Scope and metric\nare fixed at creation; delete and recreate to change them.\n\nIf `actions` is included, the entire action list is replaced (existing\naction rows are deleted and re-inserted). Requires org owner role.","operationId":"updateNotificationRule","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RuleResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error - Request validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["notifications"],"summary":"Delete a rule","description":"Delete a rule. Cascades to its actions, per-site firing state, and\nsend history. Cannot be undone. Requires org owner role.","operationId":"deleteNotificationRule","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/notification-rules/{rule_id}/test":{"post":{"tags":["notifications"],"summary":"Send a synthetic test notification","description":"Send a synthetic notification through every active action of this rule,\nusing fake values for the template variables (so you can verify that\nemail delivery, webhook signing, Slack formatting etc. all work end to\nend). Nothing about the rule's firing state changes; no `send` row is\nrecorded. Requires org owner role.","operationId":"testNotificationRule","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestSendResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/notification-rules/{rule_id}/evaluate":{"post":{"tags":["notifications"],"summary":"Evaluate now (dry-run)","description":"Run a single dry-run of the rule against live analytics data and\nreturn the observed value per site plus whether the condition is currently\nsatisfied. No notification is dispatched and no state is written; useful\nfor answering \"would this fire right now?\" without waiting for the worker\nor changing anything.","operationId":"evaluateNotificationRule","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluateResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/notification-rules/{rule_id}/sends":{"get":{"tags":["notifications"],"summary":"Notification history for a rule","description":"Paginated history of notifications actually sent for this rule, newest\nfirst. Each row includes the metric value at fire time, the full context\nsnapshot that was rendered into the notification, and the per-action\ndelivery log (status, delivered / failed counts, error messages).\n\nThis is what powers the \"History\" tab in the rule detail dialog.","operationId":"listNotificationSends","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Rule Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_SendResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/partner/clients":{"get":{"tags":["partners"],"summary":"List Clients","description":"List client organizations managed by this partner org.","operationId":"listPartnerClients","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_PartnerClientResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["partners"],"summary":"Create Client","description":"Create a brand-new organization and link it to this partner as a client.\n\nRequires *direct* membership of the partner org at member level or above,\nand the org must carry the partner entitlement (`is_partner`).\n\nUnlike `POST /admin/partners` (which links an existing org and is admin-only),\nthis lets a partner self-provision client orgs. By default the new org gets\n**no direct member** - it is managed through partner access until a real\ncustomer takes ownership. Pass `owner_email` to invite that customer as OWNER\nin the same step (an invite email is sent; on accept they become owner).","operationId":"createPartnerClient","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerClientCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerClientResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/partner/clients/{client_org_id}":{"delete":{"tags":["partners"],"summary":"Remove Client","description":"Detach a client org from this partner, and delete it if orphaned.\n\nDirect membership of the partner org is required. Only links owned by *this*\npartner org can be removed (you can't detach another partner's client).\n\nIf, after detaching, the client org has no members and no other partner\nlinks, it is unreachable by anyone and gets fully deleted (sites, invites,\nmemberships) — mirroring the \"last member leaves → org is removed\"\nlifecycle. If the client still has members (a real customer was onboarded)\nor other partners, it survives; only this link is removed.","operationId":"removePartnerClient","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"client_org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Client Org Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/partner/usage":{"get":{"tags":["partners"],"summary":"Get Partner Usage","description":"Get aggregated beacon usage across all client organizations.","operationId":"getPartnerUsage","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerUsageResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/partner-access":{"get":{"tags":["partners"],"summary":"List Partner Access","description":"List the partner organizations that have access to this org, newest\nfirst, one page at a time.\n\nThe client's view of the `partners` relationship: shows whether — and which —\npartner org manages this org (empty `data` = none). Requires *direct*\nmembership, so a partner inspecting a client via partner access can't use\nthis to enumerate the client's relationships.","operationId":"listPartnerAccess","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedResponse_PartnerAccessResponse_"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/organizations/{org_id}/partner-access/{partner_org_id}":{"delete":{"tags":["partners"],"summary":"Revoke Partner Access","description":"Revoke a partner organization's access to this (client) org.\n\nThe mirror of `DELETE /partner/clients/{client_org_id}`, but initiated by the\n*client*. Direct membership of this org is required, which means a partner\ncan't use its own partner access to revoke itself or a rival agency, and the\nacting member always remains, so this call never orphans the org (no cascade\ndelete, unlike the partner-side removal).","operationId":"revokePartnerAccess","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Org Id"}},{"name":"partner_org_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Partner Org Id"}}],"responses":{"204":{"description":"Successful Response"},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not Found - Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/search":{"get":{"tags":["search"],"summary":"Search","description":"Search organizations, applications and sites the caller may act in.\n\nEvery organization the credential reaches is searched: direct memberships,\npartner clients, and for a platform admin's session every active\norganization. A key is cut to the organizations it was issued for and to\nits scopes - a key without `site:read` gets no sites, whatever its owner's\nrole is. Inactive organizations never appear; inactive sites and\napplications do, flagged `is_active: false`, because reactivating one\nstarts with finding it.\n\nResults come per kind, each capped at `limit`, best match first: exact\nname, then prefix, then substring, then alphabetical.","operationId":"search","security":[{"APIKeyHeader":[]}],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","maxLength":100,"description":"Substring to match, case-insensitive. Empty lists the first entries of each kind by name.","default":"","title":"Q"},"description":"Substring to match, case-insensitive. Empty lists the first entries of each kind by name."},{"name":"kinds","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"enum":["organization","application","site"],"type":"string"}},{"type":"null"}],"description":"Which kinds to search. Defaults to all three.","title":"Kinds"},"description":"Which kinds to search. Defaults to all three."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"description":"Per-kind cap.","default":20,"title":"Limit"},"description":"Per-kind cap."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authorization token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal Server Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ActionCreate":{"properties":{"type":{"$ref":"#/components/schemas/ActionType"},"is_active":{"type":"boolean","title":"Is Active","default":true},"config":{"additionalProperties":true,"type":"object","title":"Config"}},"type":"object","required":["type","config"],"title":"ActionCreate"},"ActionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"$ref":"#/components/schemas/ActionType"},"is_active":{"type":"boolean","title":"Is Active"},"config":{"additionalProperties":true,"type":"object","title":"Config"}},"type":"object","required":["id","type","is_active","config"],"title":"ActionResponse","description":"Always-masked read representation.\n\nSecrets (webhook HMAC key, Slack/Discord webhook URLs) are never echoed in\nfull. If a user needs to rotate them, they re-enter the new value on edit."},"ActionType":{"type":"string","enum":["email","webhook","slack","discord"],"title":"ActionType"},"ActionUpdate":{"properties":{"type":{"$ref":"#/components/schemas/ActionType"},"is_active":{"type":"boolean","title":"Is Active","default":true},"config":{"additionalProperties":true,"type":"object","title":"Config"}},"type":"object","required":["type","config"],"title":"ActionUpdate"},"AggregationType":{"type":"string","enum":["count","avg","sum","min","max","p50","p75","p90","p95","p99"],"title":"AggregationType","description":"Supported aggregation functions."},"AnalyticsDataPoint":{"properties":{"timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp","description":"Timestamp (present when grouping by time)"},"dimensions":{"additionalProperties":{"type":"string"},"type":"object","title":"Dimensions","description":"Dimension values for this data point"},"metrics":{"items":{"$ref":"#/components/schemas/MetricValue"},"type":"array","title":"Metrics","description":"Metric values"},"beacons":{"type":"integer","title":"Beacons","description":"Number of beacons in this bucket"},"comparison":{"anyOf":[{"$ref":"#/components/schemas/ComparisonData"},{"type":"null"}],"description":"Comparison data (when compare_to is set)"}},"type":"object","required":["metrics","beacons"],"title":"AnalyticsDataPoint","description":"Single data point in query results."},"AnalyticsQueryMeta":{"properties":{"total_rows":{"type":"integer","title":"Total Rows","description":"Total rows matching the query"},"returned_rows":{"type":"integer","title":"Returned Rows","description":"Number of rows returned"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time in milliseconds"},"query_hash":{"type":"string","title":"Query Hash","description":"Hash for debugging/caching reference"},"time_range":{"additionalProperties":true,"type":"object","title":"Time Range","description":"Applied time range"},"comparison_time_range":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Comparison Time Range","description":"Comparison time range (when compare_to is set)"},"applied_filters":{"additionalProperties":true,"type":"object","title":"Applied Filters","description":"Applied filter values"}},"type":"object","required":["total_rows","returned_rows","execution_time_ms","query_hash","time_range","applied_filters"],"title":"AnalyticsQueryMeta","description":"Metadata about the query execution."},"AnalyticsQueryRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query (required)"},"metrics":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/MapMetric"}]},"type":"array","maxItems":10,"minItems":1,"title":"Metrics","description":"Metrics to query. Strings for flat or Nested (errors.count) metrics; objects for Map-key access (e.g. resource_sizes['script']). Cache-status rates follow the pattern `(cdn|origin)_status_rate_<status>` (lowercase, e.g. cdn_status_rate_miss; `unreported` = no status sent) — AVG-only ratio 0–1 over all pageviews. `cdn_hit_rate`/`origin_hit_rate` are legacy aliases for `*_status_rate_hit`."},"aggregations":{"items":{"$ref":"#/components/schemas/AggregationType"},"type":"array","maxItems":7,"minItems":1,"title":"Aggregations","description":"Aggregation functions to apply","default":["p75"]},"group_by":{"$ref":"#/components/schemas/GroupBy","description":"Grouping configuration (time and/or dimensions)"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"compare_to":{"anyOf":[{"$ref":"#/components/schemas/CompareMode"},{"type":"null"}],"description":"Compare to previous time period"},"compare_to_release_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Compare To Release Id","description":"Compare metrics before vs after a specific release"},"limit":{"type":"integer","maximum":10000.0,"minimum":1.0,"title":"Limit","description":"Maximum rows to return","default":2500},"offset":{"type":"integer","minimum":0.0,"title":"Offset","description":"Offset for pagination","default":0},"order_by":{"anyOf":[{"$ref":"#/components/schemas/OrderBy"},{"type":"null"}],"description":"Sort configuration"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity","description":"Backing identifier for the `visitors` metric: 'stitch' (preferred — edge-derived, present under ANONYMOUS) or 'session' (consent-gated session_id). Null resolves to the per-site default (stitch unless the site only collects sessions). Ignored by all other metrics."}},"additionalProperties":false,"type":"object","required":["time_range","metrics"],"title":"AnalyticsQueryRequest","description":"Main request schema for analytics queries."},"AnalyticsQueryResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/AnalyticsDataPoint"},"type":"array","title":"Data","description":"Query result data points"},"meta":{"$ref":"#/components/schemas/AnalyticsQueryMeta","description":"Query metadata"}},"type":"object","required":["data","meta"],"title":"AnalyticsQueryResponse","description":"Response for analytics queries."},"ApiKeyCreated":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"kind":{"$ref":"#/components/schemas/ApiKeyKind"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"prefix":{"type":"string","title":"Prefix"},"last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last4"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","default":[]},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"reach":{"$ref":"#/components/schemas/CredentialReach"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"editable":{"type":"boolean","title":"Editable","default":true},"key":{"type":"string","title":"Key"}},"type":"object","required":["id","kind","prefix","reach","created_at","key"],"title":"ApiKeyCreated","description":"Response to minting: the info plus the cleartext secret, which is\nreturned exactly once and never stored."},"ApiKeyInfo":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"kind":{"$ref":"#/components/schemas/ApiKeyKind"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"prefix":{"type":"string","title":"Prefix"},"last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last4"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","default":[]},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"reach":{"$ref":"#/components/schemas/CredentialReach"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"editable":{"type":"boolean","title":"Editable","default":true}},"type":"object","required":["id","kind","prefix","reach","created_at"],"title":"ApiKeyInfo","description":"A key in the user's account. The secret is never returned - only display\nmetadata, so keys can be recognised and revoked."},"ApiKeyKind":{"type":"string","enum":["personal","org"],"title":"ApiKeyKind","description":"Where a key came from. Not a capability - only provenance.\n\nAll kinds are the same credential (same digest scheme, same auth path, same\ntable); they differ in who holds the secret, how it is presented in the UI,\nand - for an organization's key - the prefix it carries, so that a found\nsecret says where it has to be revoked. Keeping them in one table keeps one\nlookup in the hot auth path and one place where scopes are enforced."},"ApiKeyRotate":{"properties":{"current_password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Password"},"totp_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Totp Code"},"passkey_challenge_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Passkey Challenge Id"},"passkey_assertion":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Passkey Assertion"},"grace_period_hours":{"type":"integer","maximum":24.0,"minimum":0.0,"title":"Grace Period Hours","default":0}},"type":"object","title":"ApiKeyRotate","description":"Replace a key's secret, optionally letting the old one live a little.\n\nThe successor copies name, scopes and reach, so nothing about what the\ncredential may do changes - only the secret does. Rotating therefore carries\nthe mint conditions: whoever does it sees a new secret, and it is checked\nagainst what they hold today rather than what the original minter held."},"ApplicationCreate":{"properties":{"name":{"type":"string","maxLength":255,"title":"Name","default":"Default"},"environment":{"$ref":"#/components/schemas/Environment","default":"prod"},"data_retention_days":{"type":"integer","title":"Data Retention Days","default":90},"store_stitch":{"type":"boolean","title":"Store Stitch","default":false},"count_visitors_by":{"$ref":"#/components/schemas/VisitorIdentity","default":"stitch"},"site_policy":{"$ref":"#/components/schemas/SitePolicy","default":"open"},"collect_sessions":{"type":"boolean","title":"Collect Sessions","default":false},"collect_fetch_xhr":{"type":"boolean","title":"Collect Fetch Xhr","default":false},"session_consent":{"$ref":"#/components/schemas/SessionConsent","default":"deferred"},"collect_error_messages":{"type":"boolean","title":"Collect Error Messages","default":false},"collect_error_frames":{"type":"boolean","title":"Collect Error Frames","default":false},"collect_query_keys":{"type":"boolean","title":"Collect Query Keys","default":false},"collect_query_values_for":{"items":{"type":"string"},"type":"array","maxItems":20,"title":"Collect Query Values For"},"pagetype_ruleset":{"type":"string","title":"Pagetype Ruleset","default":""},"pagetype_rules":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageTypeRule"},"type":"array"},{"type":"null"}],"title":"Pagetype Rules"},"checkout_tracking":{"type":"boolean","title":"Checkout Tracking","default":true},"checkout_cart_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Cart Paths"},"checkout_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Paths"},"checkout_success_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Success Paths"},"preset":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preset"},"collector_mode":{"$ref":"#/components/schemas/CollectorMode","default":"default"},"collector_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Collector Endpoint"},"source_version":{"type":"string","maxLength":20,"title":"Source Version","default":"v1"}},"type":"object","title":"ApplicationCreate","description":"Provision an application (a tracking embed). The collection config applies\nto every domain the app is embedded on. data_retention_days / store_stitch /\ncount_visitors_by are the per-domain DEFAULTS its member sites inherit (a site\ncan override)."},"ApplicationHit":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"environment":{"$ref":"#/components/schemas/Environment"},"is_active":{"type":"boolean","title":"Is Active"},"organization":{"$ref":"#/components/schemas/SearchOrganizationRef"}},"type":"object","required":["id","name","environment","is_active","organization"],"title":"ApplicationHit"},"ApplicationResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"name":{"type":"string","title":"Name"},"environment":{"$ref":"#/components/schemas/Environment"},"data_retention_days":{"type":"integer","title":"Data Retention Days"},"store_stitch":{"type":"boolean","title":"Store Stitch"},"count_visitors_by":{"$ref":"#/components/schemas/VisitorIdentity"},"site_policy":{"$ref":"#/components/schemas/SitePolicy"},"source_hash":{"type":"string","title":"Source Hash"},"collector_hash":{"type":"string","title":"Collector Hash"},"collect_sessions":{"type":"boolean","title":"Collect Sessions"},"collect_fetch_xhr":{"type":"boolean","title":"Collect Fetch Xhr"},"session_consent":{"$ref":"#/components/schemas/SessionConsent"},"collect_error_messages":{"type":"boolean","title":"Collect Error Messages"},"collect_error_frames":{"type":"boolean","title":"Collect Error Frames"},"collect_query_keys":{"type":"boolean","title":"Collect Query Keys"},"collect_query_values_for":{"items":{"type":"string"},"type":"array","title":"Collect Query Values For","default":[]},"pagetype_ruleset":{"type":"string","title":"Pagetype Ruleset","default":""},"pagetype_rules":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageTypeRule"},"type":"array"},{"type":"null"}],"title":"Pagetype Rules"},"checkout_tracking":{"type":"boolean","title":"Checkout Tracking","default":true},"checkout_cart_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Cart Paths"},"checkout_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Paths"},"checkout_success_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Success Paths"},"collector_mode":{"$ref":"#/components/schemas/CollectorMode"},"collector_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Collector Endpoint"},"source_version":{"type":"string","title":"Source Version"},"proxy_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Proxy Secret"},"proxy_secret_redacted":{"type":"boolean","title":"Proxy Secret Redacted","default":false},"proxy_secret_previous_set":{"type":"boolean","title":"Proxy Secret Previous Set","default":false},"is_active":{"type":"boolean","title":"Is Active"},"site_count":{"type":"integer","title":"Site Count","default":0},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","organization_id","name","environment","data_retention_days","store_stitch","count_visitors_by","site_policy","source_hash","collector_hash","collect_sessions","collect_fetch_xhr","session_consent","collect_error_messages","collect_error_frames","collect_query_keys","collector_mode","collector_endpoint","source_version","is_active","created_at","updated_at"],"title":"ApplicationResponse"},"ApplicationSiteCreate":{"properties":{"domain":{"type":"string","title":"Domain"},"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name"}},"type":"object","required":["domain"],"title":"ApplicationSiteCreate","description":"Adopt a domain into an application as a child site.\n\nDeliberately minimal: the collection config is the application's, applied at\ningest, so only the domain (and an optional display name) are needed. The\ncreated site carries NO own embed — it is served/collected via the\napplication's. Typically called with a hostname from the discovery list."},"ApplicationUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Name"},"environment":{"anyOf":[{"$ref":"#/components/schemas/Environment"},{"type":"null"}]},"data_retention_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Data Retention Days"},"store_stitch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Store Stitch"},"count_visitors_by":{"anyOf":[{"$ref":"#/components/schemas/VisitorIdentity"},{"type":"null"}]},"site_policy":{"anyOf":[{"$ref":"#/components/schemas/SitePolicy"},{"type":"null"}]},"collect_sessions":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Collect Sessions"},"collect_fetch_xhr":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Collect Fetch Xhr"},"session_consent":{"anyOf":[{"$ref":"#/components/schemas/SessionConsent"},{"type":"null"}]},"collect_error_messages":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Collect Error Messages"},"collect_error_frames":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Collect Error Frames"},"collect_query_keys":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Collect Query Keys"},"collect_query_values_for":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":20},{"type":"null"}],"title":"Collect Query Values For"},"pagetype_ruleset":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pagetype Ruleset"},"pagetype_rules":{"anyOf":[{"items":{"$ref":"#/components/schemas/PageTypeRule"},"type":"array"},{"type":"null"}],"title":"Pagetype Rules"},"checkout_tracking":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Checkout Tracking"},"checkout_cart_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Cart Paths"},"checkout_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Paths"},"checkout_success_paths":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Success Paths"},"collector_mode":{"anyOf":[{"$ref":"#/components/schemas/CollectorMode"},{"type":"null"}]},"collector_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Collector Endpoint"},"source_version":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Source Version"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"type":"object","title":"ApplicationUpdate"},"AuditAction":{"type":"string","enum":["org.created","org.deleted","org.consent_changed","org.plan_changed","org.partner_changed","org.approval_changed","org.ownership_transferred","org.member_added","org.member_removed","org.member_role_changed","partner.added","partner.removed","billing.trial_requested","billing.trial_granted","billing.trial_rejected","billing.checkout_started","billing.activated","billing.payment_failed","billing.past_due","billing.canceled","billing.discount_changed","billing.plan_changed","billing.downgrade_scheduled","billing.addon_purchased","billing.addon_changed","billing.payment_method_updated","billing.chargeback","billing.refunded","site.created","site.updated","site.deleted","site.hashes_rotated","org_tracker.created","org_tracker.updated","org_tracker.deleted","org_tracker.hashes_rotated","org_tracker.proxy_secret_rotated","org_tracker.proxy_secret_disabled","org_tracker.site_assigned","org_tracker.site_unassigned","synthetic_page.created","synthetic_page.updated","synthetic_page.deleted","user.status_changed","api_key.regenerated","app_token.issued","app_token.revoked","api_key.issued","api_key.revoked","api_key.updated","api_key.rotated","passkey.registered","passkey.removed"],"title":"AuditAction","description":"Audited actions. Extend as more events become worth recording."},"AuditLogEntry":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"action":{"$ref":"#/components/schemas/AuditAction"},"actor_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Actor User Id"},"actor_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Email"},"actor_api_key_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Actor Api Key Id"},"actor_grant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Actor Grant Id"},"actor_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Actor Label"},"target_type":{"anyOf":[{"$ref":"#/components/schemas/AuditTargetType"},{"type":"null"}]},"target_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Target Id"},"meta":{"additionalProperties":true,"type":"object","title":"Meta"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","action","actor_user_id","actor_email","target_type","target_id","meta","created_at"],"title":"AuditLogEntry","description":"One recorded change in the audit trail.\n\n**Who acted**, and a credential is as real an answer as a person:\n\n- a person acted: `actor_user_id` + `actor_email`\n- an organization's own key acted: `actor_api_key_id` + `actor_label`\n- an org-owned connected app acted: `actor_grant_id` + `actor_label`\n- a **personal** connected app acted: both - `actor_user_id` + `actor_email`\n  for the person who is accountable, and `actor_grant_id` + `actor_label`\n  for the connection they acted through. It is the one combination that\n  appears, and it exists because \"she did it herself\" and \"the assistant she\n  connected did it\" are different events.\n\n`actor_label` is resolved when the entry is read, so an entry whose\ncredential has since been deleted comes back with the id and no label. The\nperson's address is snapshotted instead (`actor_email`), because a deleted\nuser leaves nothing to resolve against."},"AuditTargetType":{"type":"string","enum":["organization","site","org_tracker","synthetic_page","user","partner","app_token","api_key","passkey"],"title":"AuditTargetType"},"BacktestBucket":{"properties":{"ts":{"type":"string","format":"date-time","title":"Ts"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"is_breach":{"type":"boolean","title":"Is Breach"},"is_fire":{"type":"boolean","title":"Is Fire","default":false}},"type":"object","required":["ts","value","is_breach"],"title":"BacktestBucket"},"BacktestRequest":{"properties":{"scope_type":{"$ref":"#/components/schemas/ScopeType"},"site_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id"},"tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag"},"metric":{"type":"string","title":"Metric"},"aggregation":{"type":"string","title":"Aggregation"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity"},"operator":{"$ref":"#/components/schemas/Operator"},"condition_type":{"$ref":"#/components/schemas/ConditionType"},"threshold":{"type":"number","title":"Threshold"},"window_seconds":{"type":"integer","title":"Window Seconds"},"baseline_window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Baseline Window Seconds"},"filters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filters"},"range_days":{"anyOf":[{"type":"integer","maximum":365.0,"minimum":1.0},{"type":"null"}],"title":"Range Days"},"re_notify_after_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Re Notify After Seconds"}},"type":"object","required":["scope_type","metric","aggregation","operator","condition_type","threshold","window_seconds"],"title":"BacktestRequest","description":"The rule shape to evaluate historically. No id; rule may not yet exist."},"BacktestResponse":{"properties":{"buckets":{"items":{"$ref":"#/components/schemas/BacktestBucket"},"type":"array","title":"Buckets"},"breach_count":{"type":"integer","title":"Breach Count"},"fire_count":{"type":"integer","title":"Fire Count"},"unit":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unit"},"granularity":{"type":"string","title":"Granularity"},"range_days":{"type":"integer","title":"Range Days"}},"type":"object","required":["buckets","breach_count","fire_count","unit","granularity","range_days"],"title":"BacktestResponse"},"BeaconBreakdownsRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"BeaconBreakdownsRequest","description":"Request for the orthogonal beacon-ingestion breakdowns."},"BeaconBreakdownsResponse":{"properties":{"total_count":{"type":"integer","title":"Total Count"},"collection_mode":{"additionalProperties":{"type":"integer"},"type":"object","title":"Collection Mode"},"delivery_method":{"additionalProperties":{"type":"integer"},"type":"object","title":"Delivery Method"},"lifecycle":{"additionalProperties":{"type":"integer"},"type":"object","title":"Lifecycle"},"tracker_version":{"additionalProperties":{"type":"integer"},"type":"object","title":"Tracker Version"}},"type":"object","required":["total_count","collection_mode","delivery_method","lifecycle","tracker_version"],"title":"BeaconBreakdownsResponse","description":"Response with orthogonal beacon-count breakdowns across the\ningestion-side dimensions of the same row set.\n\nThe first three maps are fixed-enum and each sums to `total_count`;\n`tracker_version` is open-valued and capped at the top-20:\n\n- `collection_mode`: privacy class. Inferred from `session_id`: non-empty\n  means the beacon was collected in full mode (consent given or site set\n  to FULL), empty means anonymous.\n- `delivery_method`: transport channel. Server-classified at ingest from\n  request shape + tracker marker (see migration 024).\n- `lifecycle`: pageview-lifecycle stage when the beacon was emitted\n  (init / loaded / hidden / ...). Useful to gauge how often pageviews\n  reach the loaded state vs. bounce before LCP.\n- `tracker_version`: top tracker bundles by beacon volume, format\n  `YYMMDD-<git-sha>[-dirty]`. Open value space (one per build), so\n  capped at the top-20 by count to bound response size. Lets you watch\n  cache-rollover progress and spot stale builds. Empty string covers\n  legacy beacons (pre-stamp migration) and the static `<noscript>`\n  pixel which has no runtime to stamp.\n\nMaps over flat `*_count` fields so new values (additional delivery\nchannels, future lifecycle stages, new tracker builds) flow through\nwithout a schema change on either side. Frontend computes percentages\nfrom `count / total_count`."},"BeaconError":{"properties":{"fingerprint":{"type":"string","title":"Fingerprint","description":"Stable group-by key for this error signature."},"type":{"type":"string","title":"Type","description":"Error class name, e.g. TypeError or ReferenceError. Never ResourceLoadError: those are `failed_resource_loads` on the same row."},"is_first_party":{"type":"boolean","title":"Is First Party","description":"True if any captured frame sits on the page's own registrable domain, so an own bundle on a CDN subdomain counts as the site's."},"count":{"type":"integer","title":"Count","description":"Occurrences of this signature on this beacon"},"sample_message":{"type":"string","title":"Sample Message","description":"Short PII-stripped message fingerprint (≤80 chars after sanitization)"},"frames":{"items":{"$ref":"#/components/schemas/ErrorFrameInfo"},"type":"array","title":"Frames","description":"Captured stack frames (max 5). frames[0] is the throw site."},"error_class":{"type":"string","title":"Error Class","description":"Classification (migration 048): '' = real error, 'blocked' = ad-blocked tracker request (a status-0 ResourceLoadError against a known tracker host, excluded from error_count).","default":""}},"type":"object","required":["fingerprint","type","is_first_party","count","sample_message"],"title":"BeaconError","description":"One bucketed error from a beacon's structured `errors` Nested column.\n\nServer-side projection of the parallel arrays (`errors.type`,\n`errors.frame_*`, `errors.fingerprint`, …) introduced in migration 010\nand extended to multi-frame in migration 017. The tracker emits up to\nfive entries per beacon, deduplicated locally by an internal hash key\nand capped via `errors.js`."},"BeaconFailedResource":{"properties":{"host":{"type":"string","title":"Host","description":"Host that should have served the resource."},"path":{"type":"string","title":"Path","description":"Path of the resource. Empty unless the site collects error frames: without them the privacy strip keeps a path only for the exact page host, while the ownership bucket asks the registrable domain.","default":""},"count":{"type":"integer","title":"Count","description":"Failed load events for this resource on this beacon."},"is_first_party":{"type":"boolean","title":"Is First Party","description":"True when the host is on the site's own registrable domain, i.e. the failure is the operator's to fix."},"fingerprint":{"type":"string","title":"Fingerprint","description":"Group key, the same one `/analytics/failed-resources` returns."}},"type":"object","required":["host","count","is_first_party","fingerprint"],"title":"BeaconFailedResource","description":"One failed resource load from a beacon's `errors` Nested column.\n\nSame storage as BeaconError, other population: an `<img>`/`<script>`/\n`<link>` whose load failed carries exactly one frame, and that frame IS the\nresource. It is projected apart from `errors` because `error_count` stopped\ncounting these in migration 073, so a row that listed both under one name\ncontradicted its own scalars."},"BeaconFetchXhr":{"properties":{"method":{"type":"string","title":"Method","description":"HTTP method"},"host":{"type":"string","title":"Host","description":"Target host ('' = same-origin)"},"path":{"type":"string","title":"Path","description":"Templated path"},"calls":{"type":"integer","title":"Calls","description":"Calls to this endpoint on this pageview"},"sum_ms":{"type":"integer","title":"Sum Ms","description":"Total duration (ms)"},"max_ms":{"type":"integer","title":"Max Ms","description":"Slowest single call (ms)"},"errors":{"type":"integer","title":"Errors","description":"Errored calls (status >= 400 or network)"},"status_errors":{"additionalProperties":{"type":"integer"},"type":"object","title":"Status Errors","description":"Error-status distribution on this pageview (code → count)"},"duration_buckets":{"additionalProperties":{"type":"integer"},"type":"object","title":"Duration Buckets","description":"Latency histogram (bucket-upper-ms → count)"},"sync_calls":{"type":"integer","title":"Sync Calls","description":"Synchronous XHR (main-thread-blocking) calls","default":0},"aborts":{"type":"integer","title":"Aborts","description":"Aborted calls (user/navigation cancellation)","default":0},"blocked":{"type":"integer","title":"Blocked","description":"Ad-blocked status-0 calls to tracker hosts (not real failures)","default":0},"sum_bytes":{"type":"integer","title":"Sum Bytes","description":"Σ transferSize (same-origin/TAO; 0 masked)","default":0},"max_bytes":{"type":"integer","title":"Max Bytes","description":"Largest response (bytes); 0 masked","default":0},"sum_offset_ms":{"type":"integer","title":"Sum Offset Ms","description":"Σ start-offset from PV start (ms); sum_offset_ms/calls ≈ the endpoint's average waterfall position","default":0}},"type":"object","required":["method","host","path","calls","sum_ms","max_ms","errors"],"title":"BeaconFetchXhr","description":"One fetch_xhr endpoint this pageview called (from fetch_xhr_endpoints)."},"BeaconFetchXhrOutlier":{"properties":{"method":{"type":"string","title":"Method","description":"HTTP method"},"host":{"type":"string","title":"Host","description":"Target host ('' = same-origin)"},"path":{"type":"string","title":"Path","description":"Templated path"},"duration_ms":{"type":"integer","title":"Duration Ms","description":"Call duration (ms)"},"status":{"type":"integer","title":"Status","description":"HTTP status (0 = network error / unknown)"},"ttfb_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttfb Ms","description":"TTFB (ms); null = cross-origin masked"},"server_timing":{"additionalProperties":{"type":"number"},"type":"object","title":"Server Timing","description":"The call's own backend phases (name → ms) from Server-Timing — same-origin/TAO only (empty cross-origin)."}},"type":"object","required":["method","host","path","duration_ms","status"],"title":"BeaconFetchXhrOutlier","description":"One slow fetch_xhr (>500 ms) captured on this pageview (fetch_xhr_outliers)."},"BeaconLoAF":{"properties":{"script_host":{"type":"string","title":"Script Host","description":"Attributed script host ('' = unattributed)"},"script_path":{"type":"string","title":"Script Path","description":"Attributed script path (origin-relative)"},"invoker_type":{"type":"string","title":"Invoker Type","description":"Invoker type (reserved; often '' on current tracker)","default":""},"total_ms":{"type":"integer","title":"Total Ms","description":"Total blocking time attributed to this script (ms)"},"frames":{"type":"integer","title":"Frames","description":"Number of long-animation-frame occurrences"}},"type":"object","required":["script_host","script_path","total_ms","frames"],"title":"BeaconLoAF","description":"One Long-Animation-Frame script attribution on this pageview (from the `loaf` Nested)."},"BeaconRow":{"properties":{"started_at":{"type":"string","format":"date-time","title":"Started At"},"ended_at":{"type":"string","format":"date-time","title":"Ended At"},"session_id":{"type":"string","title":"Session Id"},"stitch":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stitch"},"pvid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pvid"},"url":{"type":"string","title":"Url"},"site_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id"},"version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"},"tracker_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tracker Version"},"lifecycle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lifecycle"},"delivery_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Delivery Method"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"referrer_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referrer Source"},"referrer_medium":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referrer Medium"},"utm_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Source"},"utm_medium":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Medium"},"utm_campaign":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Campaign"},"utm_term":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Term"},"utm_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Content"},"click_id_param":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Click Id Param"},"browser":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Browser"},"browser_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Browser Version"},"device_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Type"},"os":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Os"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"connection_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Connection Type"},"viewport_class":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Viewport Class"},"lcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp"},"fcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fcp"},"cls":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cls"},"inp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp"},"tbt":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tbt"},"ttfb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ttfb"},"ttfb_final":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ttfb Final"},"page_load_time":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Page Load Time"},"dom_interactive":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Dom Interactive"},"start_render":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Start Render"},"content_transfer_duration":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Content Transfer Duration"},"dns_lookup":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Dns Lookup"},"tcp_connection":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Tcp Connection"},"total_byte_weight":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Byte Weight"},"cache_hit_rate":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cache Hit Rate"},"cached_resources":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cached Resources"},"page_cached":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Page Cached"},"service_worker_active":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Service Worker Active"},"error_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Error Count"},"errors":{"items":{"$ref":"#/components/schemas/BeaconError"},"type":"array","title":"Errors","description":"Structured per-beacon JavaScript errors (top 5 by occurrence). Sourced from the ClickHouse `errors` Nested column. Failed resource loads share that column and are NOT in this list, they are `failed_resource_loads`. Empty list when no errors were captured on this beacon."},"failed_resources":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Failed Resources"},"failed_resource_loads":{"items":{"$ref":"#/components/schemas/BeaconFailedResource"},"type":"array","title":"Failed Resource Loads","description":"Resources whose load failed (top 3 by occurrence). `failed_resources` counts ALL of them, this list carries the ones that fit on the wire, so the two disagree on a page with many broken resources."},"slowest_resource_duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Slowest Resource Duration"},"resource_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Resource Count"},"bfcache_hit":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Bfcache Hit"},"nav_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nav Type"},"protocol":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Protocol"},"lcp_element":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lcp Element"},"lcp_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lcp Url"},"cls_element":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cls Element"},"third_party_duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Third Party Duration"},"third_party_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Third Party Count"},"connection_rtt":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Connection Rtt"},"connection_downlink":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Connection Downlink"},"visibility_dirty":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Visibility Dirty"},"prerendered":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Prerendered"},"activation_delta":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Activation Delta"},"lcp_is_image":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Lcp Is Image"},"lcp_discovered_via":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lcp Discovered Via"},"dominant_third_party_category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dominant Third Party Category"},"loaf_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Loaf Count"},"loaf_total_duration":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Loaf Total Duration"},"error_origin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Origin"},"cdn_cache_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cdn Cache Status"},"origin_cache_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin Cache Status"},"edge_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Edge Dur"},"origin_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Origin Dur"},"backend_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Backend Dur"},"db_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Db Dur"},"http_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Http Dur"},"render_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Render Dur"},"search_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Search Dur"},"kv_dur":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Kv Dur"},"page_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Page Type"},"origin_host":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin Host"},"logged_in":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logged In"},"cdn_age":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cdn Age"},"origin_age":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Origin Age"},"checkout_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checkout Stage"},"cart_interactions":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cart Interactions"},"cart_interaction_errors":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cart Interaction Errors"},"datacenter":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Datacenter"},"bot_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Name"},"bot_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Type"},"ua_anomaly":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ua Anomaly"},"is_datacenter":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Datacenter"},"is_bot":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Bot"},"bot_class":{"anyOf":[{"$ref":"#/components/schemas/BotClass"},{"type":"null"}]},"fetch_xhr_total_calls":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fetch Xhr Total Calls"},"fetch_xhr_total_errors":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fetch Xhr Total Errors"},"fetch_xhr_worst_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Fetch Xhr Worst Ms"},"fetch_xhrs":{"items":{"$ref":"#/components/schemas/BeaconFetchXhr"},"type":"array","title":"Fetch Xhrs","description":"Endpoints this pageview called (fetch_xhr_endpoints)"},"fetch_xhr_outliers":{"items":{"$ref":"#/components/schemas/BeaconFetchXhrOutlier"},"type":"array","title":"Fetch Xhr Outliers","description":"Slow fetch_xhrs (>500ms) on this pageview"},"server_timing":{"items":{"$ref":"#/components/schemas/BeaconServerTiming"},"type":"array","title":"Server Timing","description":"Server-Timing custom keys (server_timing_dur + server_timing_desc maps)"},"loaf":{"items":{"$ref":"#/components/schemas/BeaconLoAF"},"type":"array","title":"Loaf","description":"Long-Animation-Frame per-script attribution on this pageview (loaf Nested)"},"third_party_by_category":{"additionalProperties":{"type":"integer"},"type":"object","title":"Third Party By Category","description":"Third-party blocking time by category (category → ms)"},"third_parties":{"additionalProperties":{"type":"integer"},"type":"object","title":"Third Parties","description":"Third-party blocking time by domain (domain → ms). Empty for beacons ingested in ANONYMOUS mode (domain keys suppressed at the edge)."},"resource_counts":{"additionalProperties":{"type":"integer"},"type":"object","title":"Resource Counts","description":"Resource count by type (type → count)"},"resource_sizes":{"additionalProperties":{"type":"integer"},"type":"object","title":"Resource Sizes","description":"Resource transfer size by type (type → bytes)"},"resource_durations":{"additionalProperties":{"type":"integer"},"type":"object","title":"Resource Durations","description":"Resource duration by type (type → ms)"},"cart_interaction_kinds":{"additionalProperties":{"type":"integer"},"type":"object","title":"Cart Interaction Kinds","description":"Cart-interaction kind → calls (add/change/remove/other), where the endpoint reveals it. Empty when the pageview issued none."}},"type":"object","required":["started_at","ended_at","session_id","url"],"title":"BeaconRow","description":"One beacon (page view) row. Matches BEACON_ROW_FIELD_MAP.\n\nClosed schema: adding new columns requires updating both BEACON_ROW_FIELD_MAP\nand this model. The TS OpenAPI client is more useful with a closed shape than\na permissive `extra: allow`."},"BeaconServerTiming":{"properties":{"key":{"type":"string","title":"Key","description":"Server-Timing metric name"},"dur":{"type":"number","title":"Dur","description":"Reported duration (ms); 0 = desc-only categorical key"},"desc":{"type":"string","title":"Desc","description":"Server-Timing description (operator header text)","default":""}},"type":"object","required":["key","dur"],"title":"BeaconServerTiming","description":"One Server-Timing custom key on this pageview.\n\nBuilt from the union of the `server_timing_dur` and `server_timing_desc`\nmaps, so a categorical key the operator sent without a duration (e.g.\n`Server-Timing: pop;desc=\"DE-1331\"`) is surfaced too: it arrives with\ndur=0.0 and a non-empty desc."},"BeaconsOrder":{"type":"string","enum":["started_at_desc","started_at_asc"],"title":"BeaconsOrder","description":"Legacy sort values for /analytics/beacons, kept for wire compatibility.\n\nNew callers should send a BeaconsOrderBy object instead; \"started_at_desc\"\nis equivalent to {\"field\": \"started_at\", \"direction\": \"desc\"}."},"BeaconsOrderBy":{"properties":{"field":{"type":"string","title":"Field","description":"Row field to sort by (any scalar BeaconRow field)"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction","default":"desc"}},"additionalProperties":false,"type":"object","required":["field"],"title":"BeaconsOrderBy","description":"Sort configuration for /analytics/beacons: any scalar row field.\n\nRows with a NULL sort value always sink to the end regardless of\ndirection (matching the client-side sort the dashboard applies), and\nstarted_at + session_id act as tiebreakers so pagination stays stable."},"BeaconsRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"error_fingerprint":{"anyOf":[{"type":"string","maxLength":16},{"type":"null"}],"title":"Error Fingerprint","description":"Scope the list to pageviews carrying this signature (`errors.fingerprint`). Handled here, NOT via the shared Filters, because it's a Nested-array column that only exists on `beacons` — putting it in Filters would break the rollup-routed aggregate endpoints. Powers the /error page's 'open in Explorer' drill-down."},"error_fingerprint_kind":{"$ref":"#/components/schemas/ErrorFingerprintKind","description":"Which population `error_fingerprint` belongs to. Both halves of the `errors` column carry fingerprints, so a resource signature scoped as an error would silently return nothing.","default":"error"},"server_timing":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Server Timing","description":"Scope the list by custom Server-Timing keys: `{key: [desc, ...]}`. An empty value list matches on key PRESENCE (`{\"elasticsearch\": []}` = every pageview whose origin reported that key, timed or categorical); a non-empty list matches the categorical desc value (`{\"pop\": [\"DE-1331\"]}`). Multiple keys are ANDed, multiple values for one key are ORed. Handled here, NOT via the shared Filters, for the same reason as `error_fingerprint`: `server_timing_dur`/`server_timing_desc` are Map columns that the aggregate rollups do not store, so putting this in Filters would let it be silently ignored on the rollup-routed endpoints."},"limit":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Limit","description":"Max rows per page","default":100},"offset":{"type":"integer","minimum":0.0,"title":"Offset","description":"Pagination offset (0-based)","default":0},"order_by":{"anyOf":[{"$ref":"#/components/schemas/BeaconsOrder"},{"$ref":"#/components/schemas/BeaconsOrderBy"}],"title":"Order By","description":"Sort order. Either a legacy string (started_at_desc/started_at_asc) or a {field, direction} object over any scalar row field; NULL values always sort last. Default shows most recent first.","default":"started_at_desc"},"fields":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Fields","description":"Optional field projection. Null/omitted returns the full whitelist. started_at, session_id, url are always included regardless."},"live":{"type":"boolean","title":"Live","description":"Live view: skip the 30s-cached total count so brand-new beacons surface immediately. `has_more` is derived by over-fetching one row; `total_matched` is returned as null (unknown). Use for an auto-refreshing 'latest requests' table; leave off for normal paginated browsing where the exact total matters.","default":false}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"BeaconsRequest","description":"Row-level drill-down request: individual beacons matching filters.\n\nResponse shape is row-per-beacon (no metric aggregation). Pair with\n/analytics/query when the user needs to go from an aggregate row to the\nspecific beacons behind it."},"BeaconsResponse":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/BeaconRow"},"type":"array","title":"Rows","description":"Matching beacons (up to limit)"},"total_matched":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Matched","description":"Total rows matching filters (ignoring limit/offset); UI uses this to decide whether pagination is worth showing. Null in `live` mode, where the cached count is skipped for freshness and only `has_more` is known."},"has_more":{"type":"boolean","title":"Has More","description":"More rows beyond this page. Normal mode: offset + len(rows) < total_matched. Live mode: derived by over-fetching one row."},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["rows","total_matched","has_more","execution_time_ms"],"title":"BeaconsResponse","description":"Response for /analytics/beacons."},"BotClass":{"type":"string","enum":["bot","suspect","none"],"title":"BotClass","description":"Derived traffic verdict (never stored; see constants.BOT_CLASS_PREDICATES\nfor the SQL rules - a lockstep test pins the two value sets together)."},"CheckoutFunnelRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity","description":"Identifier to group the funnel by: 'stitch' or 'session'. Null → the per-site default (stitch preferred), same resolution as /visitors. The funnel needs a stored identifier; without one there is nothing to follow from cart to success."},"granularity":{"type":"string","enum":["hour","day","auto"],"title":"Granularity","description":"Bucket size of the series: 'hour'/'day', or 'auto' (default; <=48h windows give hourly, longer daily).","default":"auto"}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"CheckoutFunnelRequest","description":"Request for the checkout funnel + its time series."},"CheckoutFunnelResponse":{"properties":{"identity":{"type":"string","title":"Identity","description":"Identifier the funnel was grouped by: stitch | session"},"steps":{"items":{"$ref":"#/components/schemas/FunnelStep"},"type":"array","title":"Steps","description":"Funnel steps in funnel order"},"cart_interactions":{"type":"integer","title":"Cart Interactions","description":"Visitors with at least one cart interaction (fetch/XHR cart mutation) over the window. A signal BESIDE the funnel steps: it only says an interaction happened, undercounts by design (fetch_xhr coverage), and is therefore not a conversion baseline.","default":0},"cart_interaction_kinds":{"additionalProperties":{"type":"integer"},"type":"object","title":"Cart Interaction Kinds","description":"Kind -> visitors with >=1 interaction of that kind, where the shop system's endpoint reveals the kind: add | change | remove | other. 'change' includes Shopify's qty-0 removes; 'other' = the kind only lives in the POST body (never read). Only kinds that occurred appear."},"granularity":{"type":"string","title":"Granularity","description":"Resolved bucket size: hour | day"},"timeseries":{"items":{"$ref":"#/components/schemas/FunnelBucket"},"type":"array","title":"Timeseries","description":"Series bucketed by funnel entry time"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["identity","steps","granularity","timeseries","execution_time_ms"],"title":"CheckoutFunnelResponse","description":"Checkout funnel over the window plus its entry-day series."},"CheckoutJourney":{"properties":{"id":{"type":"string","title":"Id","description":"Visitor identifier (stitch hex or session_id)"},"matched_at":{"type":"string","format":"date-time","title":"Matched At","description":"Start of their latest matching pageview"},"pages":{"items":{"$ref":"#/components/schemas/CheckoutJourneyPageview"},"type":"array","title":"Pages","description":"Chronological pageviews"}},"type":"object","required":["id","matched_at","pages"],"title":"CheckoutJourney","description":"One visitor's pageviews around their funnel hit."},"CheckoutJourneyPageview":{"properties":{"url":{"type":"string","title":"Url"},"started_at":{"type":"string","format":"date-time","title":"Started At"},"ended_at":{"type":"string","format":"date-time","title":"Ended At"},"checkout_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checkout Stage","description":"Funnel stage of THIS pageview; null outside the funnel"},"cart_interactions":{"type":"integer","title":"Cart Interactions","description":"Cart interactions (fetch/XHR cart mutations) this pageview issued","default":0},"cart_interaction_errors":{"type":"integer","title":"Cart Interaction Errors","description":"Of those, failed ones (HTTP >= 400 or network failure) - the 'cart actions are failing' signal","default":0},"cart_interaction_kinds":{"additionalProperties":{"type":"integer"},"type":"object","title":"Cart Interaction Kinds","description":"Kind -> calls (add/change/remove/other), where the endpoint reveals it"},"page_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Page Type"},"nav_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nav Type"},"lcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp"},"fcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fcp"},"cls":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cls"},"inp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp"},"ttfb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ttfb"}},"type":"object","required":["url","started_at","ended_at"],"title":"CheckoutJourneyPageview","description":"One pageview inside a checkout journey.\n\nDeliberately narrower than `VisitorPageVisit`: a journey list projects many\nrows per visitor, so it carries the funnel hook, the URL and the four core\nvitals (which is what \"web vitals per funnel step\" needs) rather than the\nfull per-pageview record. `/visitors/detail` remains the full drill-in."},"CheckoutJourneysRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity","description":"Identifier to group by; null → the per-site default"},"stage":{"type":"string","enum":["cart","checkout","success"],"title":"Stage","description":"Which stage a visitor must have hit to be included","default":"success"},"full_journey":{"type":"boolean","title":"Full Journey","description":"True: every pageview of the matching visitors, in order - the whole journey around the hit. False: only the matching pageviews themselves.","default":true},"limit":{"type":"integer","maximum":200.0,"minimum":1.0,"title":"Limit","description":"Max visitors (not pageviews)","default":50}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"CheckoutJourneysRequest","description":"Request for the journeys behind a funnel step."},"CheckoutJourneysResponse":{"properties":{"identity":{"type":"string","title":"Identity","description":"Identifier the journeys were grouped by"},"stage":{"type":"string","title":"Stage","description":"Stage the visitors were selected by"},"journeys":{"items":{"$ref":"#/components/schemas/CheckoutJourney"},"type":"array","title":"Journeys"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["identity","stage","journeys","execution_time_ms"],"title":"CheckoutJourneysResponse"},"CollectorMode":{"type":"string","enum":["default","custom","relative"],"title":"CollectorMode","description":"How the served tracker bundle is told where to POST beacons.\n\nDEFAULT  → fastmon's shared collector (`settings.COLLECTOR_URL`); third-party.\nCUSTOM   → an explicit absolute `collector_endpoint` URL. Covers both a\n           first-party setup on the customer's own domain AND a third-party\n           custom collector host — the browser decides 1P/3P at runtime by\n           comparing that host to the page origin; we don't store which.\nRELATIVE → a host-less relative `/c/<hash>`, resolved same-origin against\n           whatever domain the page runs on. First-party without pinning a\n           host — the natural fit for an org tracker embedded across N\n           domains. `collector_endpoint` is unused (must be empty)."},"CompareMode":{"type":"string","enum":["previous_period","previous_week","previous_month"],"title":"CompareMode","description":"Comparison time range modes."},"ComparisonData":{"properties":{"metrics":{"items":{"$ref":"#/components/schemas/MetricValue"},"type":"array","title":"Metrics","description":"Comparison metric values"},"beacons":{"type":"integer","title":"Beacons","description":"Number of samples in comparison period"},"change_percent":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Change Percent","description":"Percent change from comparison (negative = improvement for timing)"}},"type":"object","required":["metrics","beacons"],"title":"ComparisonData","description":"Comparison data for a data point."},"ConditionType":{"type":"string","enum":["absolute","relative_change"],"title":"ConditionType"},"ConnectionInfo":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"client_id":{"type":"string","title":"Client Id"},"client_name":{"type":"string","title":"Client Name"},"is_verified":{"type":"boolean","title":"Is Verified","default":false},"redirect_uris":{"items":{"type":"string"},"type":"array","title":"Redirect Uris","default":[]},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","default":[]},"approved_by_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Approved By User Id"},"credential_owner":{"type":"string","title":"Credential Owner","default":"organization"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"}},"type":"object","required":["id","client_id","client_name","organization_id","created_at"],"title":"ConnectionInfo","description":"One connected app, as the merchant should see it.\n\n`client_name` is self-declared at registration and `is_verified` says\nwhether we vouch for it, which for anything self-registered is never. The\nsignal the merchant can actually judge is `redirect_uris`: those are the\naddresses the connection's codes were sent to, and for a shop plugin that\nis their own domain."},"CredentialReach":{"properties":{"scope":{"type":"string","title":"Scope"},"partner_org_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Partner Org Id"},"organization_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Organization Ids","default":[]},"organization_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organization Count"}},"type":"object","required":["scope"],"title":"CredentialReach","description":"How far a credential reaches, in organizations.\n\nDeliberately not a `cross_tenant` boolean and deliberately not keyed on the\nowner being an admin - that would miss the ordinary case. A member of a\npartner organization reaches every client org it manages; anyone in several\norganizations reaches several. What matters is the reach itself.\n\nThe unbounded values are a promise about organizations that do not exist\nyet: the owner may be added to one tomorrow. That is the same unbounded\ngrant a wildcard scope would have been, one level up\n(docs/plan/credentials.md §2.3) - which is why **no API key can report\nthem**. They describe sessions only."},"CursorPaginatedResponse_VisitorSummaryItem_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/VisitorSummaryItem"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/CursorPaginationMeta"}},"type":"object","required":["data","meta"],"title":"CursorPaginatedResponse[VisitorSummaryItem]"},"CursorPaginationMeta":{"properties":{"limit":{"type":"integer","title":"Limit"},"has_more":{"type":"boolean","title":"Has More"},"next_cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Cursor"}},"type":"object","required":["limit","has_more"],"title":"CursorPaginationMeta","description":"Meta for ClickHouse-backed cursor-paginated lists.\n\n`total` is intentionally absent: COUNT(*) over beacon tables is too\nexpensive. Clients rely on `has_more` + `next_cursor` instead."},"DeviceComparison":{"properties":{"device":{"type":"string","title":"Device"},"lab_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lab Score"},"experience_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Experience Score"},"experience_grade":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Experience Grade"},"field_samples":{"type":"integer","title":"Field Samples"},"field_sufficient":{"type":"boolean","title":"Field Sufficient"},"metrics":{"items":{"$ref":"#/components/schemas/MetricComparison"},"type":"array","title":"Metrics"},"field_inp_p75":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Field Inp P75"},"lab_tbt":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lab Tbt"}},"type":"object","required":["device","lab_score","experience_score","experience_grade","field_samples","field_sufficient","metrics","field_inp_p75","lab_tbt"],"title":"DeviceComparison"},"ElementTargetItem":{"properties":{"target":{"type":"string","title":"Target","description":"Bounded CSS selector path (e.g. '#hero>img.banner')"},"count":{"type":"integer","title":"Count","description":"Pageviews attributing this target (exact)"},"share_pct":{"type":"number","title":"Share Pct","description":"Share of the group's attributed pageviews (0-100)"},"avg_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Value","description":"Average metric value on those pageviews (ms for lcp/inp, score for cls)"}},"type":"object","required":["target","count","share_pct"],"title":"ElementTargetItem","description":"One ranked element target within a group."},"ElementTargetsGroup":{"properties":{"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key","description":"Group key (URL), null for group_by=none"},"pageviews_with_target":{"type":"integer","title":"Pageviews With Target","description":"Pageviews in this group carrying a non-empty target"},"targets":{"items":{"$ref":"#/components/schemas/ElementTargetItem"},"type":"array","title":"Targets","description":"Ranked targets, most frequent first"}},"type":"object","required":["pageviews_with_target","targets"],"title":"ElementTargetsGroup","description":"Ranked targets for one group (one URL, or the whole scope)."},"ElementTargetsRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query (required)"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"metric":{"type":"string","enum":["lcp","cls","inp"],"title":"Metric","description":"Which vital's element attribution to rank"},"by":{"type":"string","enum":["element","resource_url"],"title":"By","description":"'element' ranks the CSS selector path; 'resource_url' ranks the LCP resource URL (only valid for metric='lcp')","default":"element"},"group_by":{"type":"string","enum":["none","url"],"title":"Group By","description":"'url' ranks targets per page; 'none' site-wide","default":"none"},"limit":{"type":"integer","maximum":25.0,"minimum":1.0,"title":"Limit","description":"Top-N targets per group","default":10},"groups_limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Groups Limit","description":"Top-N groups by attributed pageviews (group_by=url)","default":20}},"additionalProperties":false,"type":"object","required":["time_range","metric"],"title":"ElementTargetsRequest","description":"Request for the element-targets breakdown (migration-053 selector paths).\n\nGeneric over the three attributed vitals: which ELEMENT is the LCP /\nthe largest layout shift / the reported INP interaction target. The\nselector columns are deliberately not query-builder dimensions\n(high-cardinality GROUP BY hazard); this endpoint ranks them via a\nbounded-state topK instead."},"ElementTargetsResponse":{"properties":{"metric":{"type":"string","title":"Metric","description":"The requested vital (lcp/cls/inp)"},"groups":{"items":{"$ref":"#/components/schemas/ElementTargetsGroup"},"type":"array","title":"Groups","description":"group_by=none → exactly one group; group_by=url → top groups"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["metric","groups","execution_time_ms"],"title":"ElementTargetsResponse","description":"Response for the element-targets breakdown."},"Environment":{"type":"string","enum":["prod","dev"],"title":"Environment","description":"Deployment environment of an application. Billing-relevant: PROD apps are\nbilled, DEV apps are not (see the billing module). Defaults to PROD — the\nrevenue-safe fallback, so a forgotten value is never silently unbilled."},"ErrorBody":{"properties":{"code":{"type":"string","title":"Code"},"message":{"type":"string","title":"Message"},"request_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Request Id"},"doc_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Doc Url"},"details":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Details"}},"type":"object","required":["code","message"],"title":"ErrorBody"},"ErrorBreakdown":{"properties":{"top":{"items":{"$ref":"#/components/schemas/ErrorBreakdownEntry"},"type":"array","title":"Top","description":"Top-N entries, desc by count"},"distinct_total":{"type":"integer","title":"Distinct Total","description":"Total distinct values across the dimension"}},"type":"object","required":["top","distinct_total"],"title":"ErrorBreakdown","description":"Top-N plus totals for one breakdown dimension."},"ErrorBreakdownDim":{"type":"string","enum":["url","browser","device","os","country"],"title":"ErrorBreakdownDim","description":"Dimensions available for error detail breakdowns."},"ErrorBreakdownEntry":{"properties":{"key":{"type":"string","title":"Key","description":"Dimension value (e.g. a URL, browser name)"},"count":{"type":"integer","title":"Count","description":"Error occurrences for this value"},"visitors":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Visitors","description":"Distinct affected visitors for this value, counted over the response's resolved `identity` (stitch or session). Null if the site collects no visitor identifier."}},"type":"object","required":["key","count"],"title":"ErrorBreakdownEntry","description":"One row in a breakdown histogram."},"ErrorDetailRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity","description":"Identity backing `visitors_affected` / breakdown `visitors`: 'stitch' or 'session'. Null resolves to the per-site default."},"fingerprint":{"type":"string","maxLength":16,"minLength":1,"title":"Fingerprint"},"breakdowns":{"items":{"$ref":"#/components/schemas/ErrorBreakdownDim"},"type":"array","title":"Breakdowns","description":"Dimensions to return as top-N breakdowns"},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","description":"Max entries per breakdown dimension","default":10},"sample_size":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Sample Size","default":20},"granularity":{"anyOf":[{"type":"string","enum":["hour","day"]},{"type":"string","const":"auto"}],"title":"Granularity","description":"Time-series bucket: 'hour'/'day', or 'auto' (derived from the time range)","default":"auto"}},"additionalProperties":false,"type":"object","required":["time_range","fingerprint"],"title":"ErrorDetailRequest","description":"Request for drill-down on a single error signature.\n\nIdentified by `fingerprint` (server-computed canonical key), not the\nlegacy 4-tuple. Backfillable: if the fingerprint rule changes, an\nUPDATE rewrites every row deterministically; old request URLs become\ninvalid by design rather than silently matching the wrong bucket."},"ErrorDetailResponse":{"properties":{"summary":{"$ref":"#/components/schemas/ErrorDetailSummary"},"identity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Identity","description":"Resolved identity backing the affected-visitor counts (stitch|session); null = site collects neither identifier."},"timeseries":{"items":{"$ref":"#/components/schemas/ErrorTimeseriesPoint"},"type":"array","title":"Timeseries"},"breakdowns":{"additionalProperties":{"$ref":"#/components/schemas/ErrorBreakdown"},"type":"object","title":"Breakdowns"},"samples":{"items":{"$ref":"#/components/schemas/ErrorSample"},"type":"array","title":"Samples"},"execution_time_ms":{"type":"number","title":"Execution Time Ms"}},"type":"object","required":["summary","timeseries","breakdowns","samples","execution_time_ms"],"title":"ErrorDetailResponse","description":"Response for `/analytics/error-types/detail`."},"ErrorDetailSummary":{"properties":{"count":{"type":"integer","title":"Count"},"visitors_affected":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Visitors Affected","description":"Distinct affected visitors, counted over the response's resolved `identity` (stitch or session). Null if the site collects no visitor identifier."},"first_seen":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"First Seen"},"last_seen":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Seen"},"percentage_of_total":{"type":"number","title":"Percentage Of Total"}},"type":"object","required":["count","percentage_of_total"],"title":"ErrorDetailSummary","description":"Aggregate summary for the selected error."},"ErrorFingerprintKind":{"type":"string","enum":["error","failed_resource"],"title":"ErrorFingerprintKind","description":"Which half of the `errors` Nested a fingerprint scope means.\n\nBoth halves carry a fingerprint out of the same key space, so a caller that\nscopes to one says which list it took the key from rather than letting the\nserver guess: `/analytics/error-types` for `error`, `/analytics/failed-resources`\nfor `failed_resource`."},"ErrorFrameInfo":{"properties":{"host":{"type":"string","title":"Host","description":"Source-script hostname (no port/query)."},"path":{"type":"string","title":"Path","description":"Sanitized script path; '' on host-only frames.","default":""},"line":{"type":"integer","title":"Line","description":"Line number in the bundled file."},"column":{"type":"integer","title":"Column","description":"Column number in the bundled file."}},"type":"object","required":["host","line","column"],"title":"ErrorFrameInfo","description":"One stack frame surfaced to the dashboard.\n\nThe fields mirror the storage shape (`errors.frame_hosts/paths/lines/\ncols` per error): hostname + sanitized script path — never a query\nstring or token. `path` is \"\" wherever the wire carried a host-only\nframe: on the without-consent wire everything except first-party\nEXTERNAL script frames (docs/data_collection.md §3.9), plus rows\npredating migration 033. line/col are the raw positions; resolving\nthem to source-mapped locations is a future server-side concern, not\npart of this schema."},"ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/ErrorBody"}},"type":"object","required":["error"],"title":"ErrorResponse"},"ErrorSample":{"properties":{"started_at":{"type":"string","format":"date-time","title":"Started At","description":"Pageview start where the error occurred"},"url":{"type":"string","title":"Url"},"session_id":{"type":"string","title":"Session Id"},"browser":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Browser"},"device":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device"},"os":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Os"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}},"type":"object","required":["started_at","url","session_id"],"title":"ErrorSample","description":"Recent beacon exhibiting this error."},"ErrorSymbolicationRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"fingerprint":{"type":"string","maxLength":16,"minLength":1,"title":"Fingerprint"}},"additionalProperties":false,"type":"object","required":["time_range","fingerprint"],"title":"ErrorSymbolicationRequest","description":"Request for `/analytics/error-types/symbolicate`.\n\nCarries the same identity as the error detail. There is deliberately no URL\nparameter: the frames come from what we stored for this fingerprint, so a\ncaller cannot point our fetcher at a host of their choosing."},"ErrorSymbolicationResponse":{"properties":{"frames":{"items":{"$ref":"#/components/schemas/SymbolicatedFrame"},"type":"array","title":"Frames"},"error_type":{"type":"string","title":"Error Type","description":"The group's error type, repeated here so the stack reads alone.","default":""},"message_kind":{"type":"string","title":"Message Kind","description":"The group's message shape, repeated here for the same reason as `error_type`. Together with the top frame's `object` and `property` this is the sentence: `not_defined` plus `uc` plus `setServiceAlias` says what was called and what was missing.","default":""},"message_value":{"type":"string","title":"Message Value","description":"The identifier that shape names, '' when it names none.","default":""},"sample_message":{"type":"string","title":"Sample Message","description":"The group's message. Often the whole answer where the stack is not: a selector, a bad token, the value that failed to parse. Empty when the site does not collect messages.","default":""},"messages_collected":{"type":"boolean","title":"Messages Collected","description":"Every application in scope stores error messages, so an empty `sample_message` means the error carried none. False means the message may simply not be collected, which is the default.","default":false},"all_frames_in_libraries":{"type":"boolean","title":"All Frames In Libraries","description":"Every frame is a known library, so the mistake is in a call that is no longer on the stack. The stack was cut at five frames.","default":false},"execution_time_ms":{"type":"number","title":"Execution Time Ms"}},"type":"object","required":["frames","execution_time_ms"],"title":"ErrorSymbolicationResponse","description":"Response for `/analytics/error-types/symbolicate`."},"ErrorTimeseriesPoint":{"properties":{"t":{"type":"string","format":"date-time","title":"T"},"count":{"type":"integer","title":"Count"}},"type":"object","required":["t","count"],"title":"ErrorTimeseriesPoint","description":"One point in the error time series."},"ErrorTypeItem":{"properties":{"fingerprint":{"type":"string","title":"Fingerprint","description":"Stable group-by key for this error signature."},"error_type":{"type":"string","title":"Error Type","description":"Error type name (e.g., 'TypeError')"},"count":{"type":"integer","title":"Count","description":"Number of occurrences"},"percentage":{"type":"number","title":"Percentage","description":"Percentage of total errors"},"sample_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample Message","description":"One example error message captured for this signature, PII-stripped and capped at 80 chars. Sourced from `errors.sample_message`. Empty on a site that does not collect messages, which is the default; `message_kind` is there in every mode and is what a reader should show."},"message_kind":{"type":"string","title":"Message Kind","description":"What the browser's message says, as one of a closed list of shapes (`json_empty`, `not_defined`, `selector_invalid`, ...), or '' when the message is one the customer wrote themselves. Collected in every mode, so this is the field a diagnosis should be built on.","default":""},"message_value":{"type":"string","title":"Message Value","description":"The identifier that shape names: a property, a variable, a callee, a selector. '' when the shape names none, when the browser did not give one, or when what it gave did not look like code.","default":""},"is_first_party":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is First Party","description":"True if any captured frame's host equals the page host (server-derived). `None` if mixed across the aggregated group."},"frames":{"items":{"$ref":"#/components/schemas/ErrorFrameInfo"},"type":"array","title":"Frames","description":"Captured stack frames (max 5). frames[0] is the innermost throw site; frames[1+] expose the caller chain past framework/wrapper frames."}},"type":"object","required":["fingerprint","error_type","count","percentage"],"title":"ErrorTypeItem","description":"One error signature, keyed by `fingerprint`.\n\n`fingerprint` is the canonical group-by handle (server-computed djb2\nhash over type + frames + message shape). All other fields are display\nprojections of one row in that group."},"ErrorTypesRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"error_type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Error Type","description":"Restrict to specific error types (e.g. ['ResourceLoadError'])."},"exclude_error_type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exclude Error Type","description":"Drop these error types from the breakdown (e.g. ['ResourceLoadError'] to stop third-party resource-load noise from counting). Negative of error_type."},"exclude_hosts":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exclude Hosts","description":"Exclude error signatures whose stack frames touch any of these hosts (e.g. ['bat.bing.com'] to drop a noisy 3rd-party)."},"first_party":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"First Party","description":"Restrict to first-party (True) or third-party (False) error signatures. Matches per-signature `errors.is_first_party` (filter-then-rank: the Top-N reflects the chosen group). None = both. Note: signature-accurate, unlike the page-level `filters.error_origin`, which says whether the PAGEVIEW carried an own error."},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","description":"Max error types to return","default":10}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"ErrorTypesRequest","description":"Request for error types breakdown."},"ErrorTypesResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ErrorTypeItem"},"type":"array","title":"Data","description":"Error types with counts"},"total_errors":{"type":"integer","title":"Total Errors","description":"Total JavaScript error count. Failed resource loads are a separate signal, see /analytics/failed-resources."},"blocked_count":{"type":"integer","title":"Blocked Count","description":"Ad-blocked tracker requests in the same filter scope - surface as 'N excluded as ad-blocked', not as a failure. A subset of the blocked bucket on /analytics/failed-resources.","default":0},"own_subdomain_hosts":{"items":{"type":"string"},"type":"array","title":"Own Subdomain Hosts","description":"Hosts on the site's own registrable domain, other than the page host, that served scripts or slow resources in this scope. Filled only when a `ScriptError` row is present: a masked error cannot be attributed, but the fix (`crossorigin=\"anonymous\"` plus CORS on the host) needs a host name, and these are the ones the site owner controls. A hint, not a verdict: the beacon carries no exhaustive script-host list."},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["data","total_errors","execution_time_ms"],"title":"ErrorTypesResponse","description":"Response for error types breakdown."},"EvaluateResponse":{"properties":{"rule_id":{"type":"string","format":"uuid","title":"Rule Id"},"evaluated_at":{"type":"string","format":"date-time","title":"Evaluated At"},"results":{"items":{"$ref":"#/components/schemas/EvaluateSiteResult"},"type":"array","title":"Results"}},"type":"object","required":["rule_id","evaluated_at","results"],"title":"EvaluateResponse"},"EvaluateSiteResult":{"properties":{"site_id":{"type":"string","format":"uuid","title":"Site Id"},"domain":{"type":"string","title":"Domain"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"is_condition_met":{"type":"boolean","title":"Is Condition Met"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","required":["site_id","domain","value","is_condition_met"],"title":"EvaluateSiteResult"},"ExcludeColumn":{"type":"string","enum":["browser","device_type","os","country","connection_type","nav_type","protocol","viewport_class","dominant_third_party_category","error_origin","cdn_cache_status","origin_cache_status","page_type","origin_host","logged_in","tracker_version","datacenter","bot_name","bot_type","ua_anomaly","checkout_stage"],"title":"ExcludeColumn","description":"Columns allowed as Filters.exclude keys (NOT IN)."},"ExperienceScoreMetric":{"properties":{"metric":{"type":"string","title":"Metric","description":"Metric name (e.g., lcp, inp)"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value","description":"Raw metric value (p75)"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score","description":"Metric score 0.0–10.0"}},"type":"object","required":["metric"],"title":"ExperienceScoreMetric","description":"Score for a single metric within a segment."},"ExperienceScoreRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query (required)"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"ExperienceScoreRequest","description":"Request schema for experience score query."},"ExperienceScoreResponse":{"properties":{"segments":{"items":{"$ref":"#/components/schemas/ExperienceScoreSegment"},"type":"array","title":"Segments","description":"Scores per visitor segment"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["segments","execution_time_ms"],"title":"ExperienceScoreResponse","description":"Response for experience score query."},"ExperienceScoreSegment":{"properties":{"segment":{"type":"string","title":"Segment","description":"Segment key (all, desktop, mobile, slow)"},"label":{"type":"string","title":"Label","description":"Human-readable segment name"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score","description":"Overall score 0.0–10.0"},"grade":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grade","description":"Letter grade (A+, A, B, C, D, F)"},"beacon_count":{"type":"integer","title":"Beacon Count","description":"Number of beacons in segment"},"metrics":{"items":{"$ref":"#/components/schemas/ExperienceScoreMetric"},"type":"array","title":"Metrics","description":"Per-metric breakdown"}},"type":"object","required":["segment","label","beacon_count","metrics"],"title":"ExperienceScoreSegment","description":"Experience score for one visitor segment."},"FailedResourceBucket":{"type":"string","enum":["first_party","third_party"],"title":"FailedResourceBucket","description":"Whose host the failed resource was on. Ownership, and nothing else.\n\nThe same axis as `errors.is_first_party`, `error_origin` and\n`first_party_only`, decided by the same registrable-domain rule. Whether a\nthird-party failure was blocked or is simply broken is deliberately NOT a\nbucket: a host denylist answers \"is this a known tracker\" when the question\nis \"was this the visitor's browser\", which is a property of a population."},"FailedResourceDetailRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity","description":"Identity backing `visitors_affected` / breakdown `visitors`: 'stitch' or 'session'. Null resolves to the per-site default."},"fingerprint":{"type":"string","maxLength":16,"minLength":1,"title":"Fingerprint"},"breakdowns":{"items":{"$ref":"#/components/schemas/ErrorBreakdownDim"},"type":"array","title":"Breakdowns","description":"Dimensions to return as top-N breakdowns. `url` is the PAGE the resource failed on, not the resource itself - that one is in the summary."},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","description":"Max entries per breakdown dimension","default":10},"sample_size":{"type":"integer","maximum":100.0,"minimum":0.0,"title":"Sample Size","default":20},"granularity":{"anyOf":[{"type":"string","enum":["hour","day"]},{"type":"string","const":"auto"}],"title":"Granularity","description":"Time-series bucket: 'hour'/'day', or 'auto' (derived from the time range)","default":"auto"}},"additionalProperties":false,"type":"object","required":["time_range","fingerprint"],"title":"FailedResourceDetailRequest","description":"Request for drill-down on a single failed-resource signature.\n\nKeyed by the `fingerprint` that `/analytics/failed-resources` returns.\n`/analytics/error-types/detail` deliberately refuses that key (its\npercentage divides by the JavaScript-only `error_count`), so the two\npopulations keep separate routes rather than one route with a mode flag."},"FailedResourceDetailResponse":{"properties":{"summary":{"$ref":"#/components/schemas/FailedResourceDetailSummary"},"identity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Identity","description":"Resolved identity backing the affected-visitor counts (stitch|session); null = site collects neither identifier."},"timeseries":{"items":{"$ref":"#/components/schemas/ErrorTimeseriesPoint"},"type":"array","title":"Timeseries"},"breakdowns":{"additionalProperties":{"$ref":"#/components/schemas/ErrorBreakdown"},"type":"object","title":"Breakdowns"},"samples":{"items":{"$ref":"#/components/schemas/ErrorSample"},"type":"array","title":"Samples"},"execution_time_ms":{"type":"number","title":"Execution Time Ms"}},"type":"object","required":["summary","timeseries","breakdowns","samples","execution_time_ms"],"title":"FailedResourceDetailResponse","description":"Response for `/analytics/failed-resources/detail`."},"FailedResourceDetailSummary":{"properties":{"host":{"type":"string","title":"Host","description":"Host that should have served the resource. Empty only when the signature had no occurrences in this scope.","default":""},"path":{"type":"string","title":"Path","description":"Path of the resource, often empty - stack frames are opt-in per site (features.collect_error_frames) and without them only a resource on the exact page host keeps its path.","default":""},"bucket":{"anyOf":[{"$ref":"#/components/schemas/FailedResourceBucket"},{"type":"null"}],"description":"Ownership of the host, null when the signature had no occurrences. One value even where the scope has two: ownership is a per-site fact and the fingerprint does not carry it, so the same CDN host can be first_party for one site of a multi-site scope and third_party for another. Reported as the conservative third_party then, the same reading `/analytics/error-types` takes for `is_first_party`. The list endpoint groups by bucket and shows the split."},"count":{"type":"integer","title":"Count","description":"Failed load events for this resource."},"pageviews":{"type":"integer","title":"Pageviews","description":"Distinct pageviews the resource failed on. Duplicate-invariant, so unlike `count` it is unaffected by a pageview that sent several beacons."},"visitors_affected":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Visitors Affected","description":"Distinct affected visitors, counted over the response's resolved `identity` (stitch or session). Null if the site collects no visitor identifier."},"first_seen":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"First Seen"},"last_seen":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Seen"},"percentage_of_total":{"type":"number","title":"Percentage Of Total","description":"Share of every failed resource load in THIS request's time range and filter scope, both buckets included. Never a share of the JavaScript `error_count`: the two populations are disjoint and a percentage across them would mean nothing. It equals a share of the list endpoint's `total_failed` only where that call set no `host`/`exclude_hosts` - those narrow its total, and this request has no way to say it wants the same denominator."}},"type":"object","required":["count","pageviews","percentage_of_total"],"title":"FailedResourceDetailSummary","description":"Aggregate summary for the selected failed resource."},"FailedResourceItem":{"properties":{"bucket":{"$ref":"#/components/schemas/FailedResourceBucket","description":"first_party | third_party (ownership only)"},"host":{"type":"string","title":"Host","description":"Host of the resource that failed to load."},"path":{"type":"string","title":"Path","description":"Path of the resource, query and hash removed. Often empty: stack frames are opt-in per site (features.collect_error_frames, off by default) and without them only a resource on the EXACT page host keeps its path. The bucket uses the registrable domain, so a resource on your own CDN subdomain is first_party and still arrives host-only. Also empty when the URL was not parseable at all.","default":""},"fingerprint":{"type":"string","title":"Fingerprint","description":"Group key for the drill-down: pass it to `/analytics/beacons` as `error_fingerprint` with `error_fingerprint_kind: failed_resource`.","default":""},"count":{"type":"integer","title":"Count","description":"Failed load events."},"pageviews":{"type":"integer","title":"Pageviews","description":"Pageviews on which this resource failed."}},"type":"object","required":["bucket","host","count","pageviews"],"title":"FailedResourceItem","description":"One failing resource, keyed by host + path."},"FailedResourcesRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"bucket":{"anyOf":[{"items":{"$ref":"#/components/schemas/FailedResourceBucket"},"type":"array"},{"type":"null"}],"title":"Bucket","description":"Restrict to these buckets. Default: both."},"host":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Host","description":"Restrict to these resource hosts (exact match on the host that should have served the file). Narrows the totals too, unlike `bucket`."},"exclude_hosts":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Exclude Hosts","description":"Drop these resource hosts (e.g. a tracker every ad blocker kills). Host is the dimension that decides this list, so without it the top rows are whatever the blockers hit most and the site's own broken files sit below them. Narrows the totals too, so the numbers agree with the rows."},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","description":"Max rows to return","default":20}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"FailedResourcesRequest","description":"Request for the failed-resources breakdown."},"FailedResourcesResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/FailedResourceItem"},"type":"array","title":"Data","description":"Failing resources, most frequent first. A top-N, so the rows do not sum to the totals below. Narrowed by the request's `bucket`, if it set one."},"total_failed":{"type":"integer","title":"Total Failed","description":"Every failed load in the time range and filter scope, both buckets included. Deliberately NOT narrowed by the request's `bucket`: the point of the number is that the reader sees how the buckets compare."},"by_bucket":{"additionalProperties":{"type":"integer"},"type":"object","title":"By Bucket","description":"Failed loads per bucket (first_party / third_party), over the same unnarrowed scope as total_failed."},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["data","total_failed","execution_time_ms"],"title":"FailedResourcesResponse","description":"Response for the failed-resources breakdown.\n\nDeliberately NOT part of the error rate: a failed resource load is\ndominated by the visitor's ad blocker, which is not a defect of the site.\nThe `first_party` bucket is the half a site operator can act on."},"FetchXhrDetailRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"host":{"type":"string","title":"Host","description":"Target host ('' = same-origin) — the drill-down key"},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method","description":"Optional HTTP-method refinement"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"Optional path refinement (one endpoint)"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","description":"Max rows per block (pages/endpoints/outliers)","default":20},"order_by":{"type":"string","enum":["impact","errors","error_rate","calls"],"title":"Order By","description":"Sort key for the `pages` block","default":"impact"},"outliers":{"type":"string","enum":["slowest","failed"],"title":"Outliers","description":"Trace sample: 'slowest' (default) or 'failed' (only status >= 400)","default":"slowest"}},"additionalProperties":false,"type":"object","required":["time_range","host"],"title":"FetchXhrDetailRequest","description":"Drill-down keyed by `host` (the fetch_xhr analogue of the error-fingerprint\ndetail). `method`/`path` are optional refinements: omit them for a HOST-level\nview (all endpoints of that host), give `path` to scope to one endpoint.\nAnswers \"where do this host's calls run, and which fail (status + page)?\"."},"FetchXhrDetailResponse":{"properties":{"host":{"type":"string","title":"Host","description":"Echoed host"},"method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Method","description":"Echoed method refinement (None = all)"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"Echoed path refinement (None = all)"},"calls":{"type":"integer","title":"Calls","description":"Total calls in scope"},"errors":{"type":"integer","title":"Errors","description":"Total errored calls in scope"},"error_rate":{"type":"number","title":"Error Rate","description":"errors / calls"},"avg_ms":{"type":"number","title":"Avg Ms","description":"sum_ms / calls"},"max_ms":{"type":"integer","title":"Max Ms","description":"Slowest single call in scope"},"impact_ms":{"type":"integer","title":"Impact Ms","description":"sum_ms — total wall time in scope"},"endpoints":{"items":{"$ref":"#/components/schemas/FetchXhrEndpointItem"},"type":"array","title":"Endpoints","description":"Per (method, path) within the host, by impact"},"pages":{"items":{"$ref":"#/components/schemas/FetchXhrPageItem"},"type":"array","title":"Pages","description":"Per page (url) in scope, by impact"},"outliers":{"items":{"$ref":"#/components/schemas/FetchXhrOutlierItem"},"type":"array","title":"Outliers","description":"Individual trace calls (slow/failed) in scope — status + page"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["host","calls","errors","error_rate","avg_ms","max_ms","impact_ms","endpoints","pages","outliers","execution_time_ms"],"title":"FetchXhrDetailResponse","description":"Host (or endpoint) drill-down: overall stats + per-endpoint, per-page and\nthe individual trace calls (slow/failed, with status + page)."},"FetchXhrEndpointItem":{"properties":{"method":{"type":"string","title":"Method","description":"HTTP method (GET/POST/... or 'other')"},"host":{"type":"string","title":"Host","description":"Target host ('' = same-origin as the page)"},"path":{"type":"string","title":"Path","description":"Templated path (/api/users/:id)"},"calls":{"type":"integer","title":"Calls","description":"Calls to this endpoint"},"avg_ms":{"type":"number","title":"Avg Ms","description":"sum_ms / calls"},"max_ms":{"type":"integer","title":"Max Ms","description":"Slowest single call to this endpoint"},"errors":{"type":"integer","title":"Errors","description":"Errored calls"},"error_rate":{"type":"number","title":"Error Rate","description":"errors / calls"},"impact_ms":{"type":"integer","title":"Impact Ms","description":"Σ per-call duration (sum_ms) — frequency × latency, the impact sort key. NOT wall-clock: fetch/XHR run concurrently, so this overcounts vs elapsed time."},"status_errors":{"additionalProperties":{"type":"integer"},"type":"object","title":"Status Errors","description":"Error-status distribution over ALL calls: HTTP code → count (0 = network failure). Complete, unlike the outlier trace sample."},"p75_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"P75 Ms","description":"Approx p75 latency from the histogram"},"p95_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"P95 Ms","description":"Approx p95 latency from the histogram"},"avg_offset_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Avg Offset Ms","description":"Ø Start-Offset ab Pageview-Start (sum_offset_ms/calls) — die Balken-Position im Aggregat-Waterfall; null wenn nicht erfasst."},"sync_calls":{"type":"integer","title":"Sync Calls","description":"Synchronous XHR (main-thread-blocking) calls","default":0},"aborts":{"type":"integer","title":"Aborts","description":"Aborted calls (user/navigation cancellation)","default":0},"blocked":{"type":"integer","title":"Blocked","description":"Status-0 calls to known ad/analytics/tracker hosts, classified server-side as ad-blocked (not real failures) and excluded from `errors`.","default":0},"avg_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Avg Bytes","description":"sum_bytes / calls, averaged over ALL calls (cache hits and cross-origin-masked calls count as 0 bytes, so this under-reports for cache-heavy endpoints); null only when every call reported 0 bytes."},"max_bytes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Bytes","description":"Largest single response (bytes); null when masked"}},"type":"object","required":["method","host","path","calls","avg_ms","max_ms","errors","error_rate","impact_ms"],"title":"FetchXhrEndpointItem","description":"One endpoint template, aggregated over all pageviews (the `other` rollup\nbucket is excluded — it's only reflected in totals)."},"FetchXhrOutlierItem":{"properties":{"method":{"type":"string","title":"Method","description":"HTTP method"},"host":{"type":"string","title":"Host","description":"Target host ('' = same-origin)"},"path":{"type":"string","title":"Path","description":"Templated path"},"duration_ms":{"type":"integer","title":"Duration Ms","description":"Call duration (ms)"},"status":{"type":"integer","title":"Status","description":"HTTP status (0 = network error / unknown)"},"ttfb_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ttfb Ms","description":"TTFB (ms); null = cross-origin masked"},"page":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Page","description":"Page URL the call ran on (the beacon's `url`)"},"server_timing":{"additionalProperties":{"type":"number"},"type":"object","title":"Server Timing","description":"The call's own backend phases (name → ms) from Server-Timing — the mini-waterfall; same-origin/TAO only (empty cross-origin)."}},"type":"object","required":["method","host","path","duration_ms","status"],"title":"FetchXhrOutlierItem","description":"One slow individual call (>500 ms) for debug context."},"FetchXhrPageItem":{"properties":{"url":{"type":"string","title":"Url","description":"Page URL"},"calls":{"type":"integer","title":"Calls","description":"Calls to the endpoint from this page"},"avg_ms":{"type":"number","title":"Avg Ms","description":"sum_ms / calls"},"max_ms":{"type":"integer","title":"Max Ms","description":"Slowest single call from this page"},"errors":{"type":"integer","title":"Errors","description":"Errored calls"},"error_rate":{"type":"number","title":"Error Rate","description":"errors / calls"},"impact_ms":{"type":"integer","title":"Impact Ms","description":"sum_ms — total wall time, the impact sort key"},"status_errors":{"additionalProperties":{"type":"integer"},"type":"object","title":"Status Errors","description":"Error-status distribution on this page: HTTP code → count (0 = network)."}},"type":"object","required":["url","calls","avg_ms","max_ms","errors","error_rate","impact_ms"],"title":"FetchXhrPageItem","description":"One page an endpoint runs on, aggregated over all pageviews of that page."},"FetchXhrRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","description":"Max endpoints (endpoints block)","default":20},"outlier_limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Outlier Limit","description":"Max outliers","default":20}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"FetchXhrRequest","description":"Request for the fetch_xhr (fetch/XHR) dashboard panel."},"FetchXhrResponse":{"properties":{"totals":{"$ref":"#/components/schemas/FetchXhrTotals","description":"Aggregate counters"},"endpoints":{"items":{"$ref":"#/components/schemas/FetchXhrEndpointItem"},"type":"array","title":"Endpoints","description":"Per-endpoint aggregates"},"outliers":{"items":{"$ref":"#/components/schemas/FetchXhrOutlierItem"},"type":"array","title":"Outliers","description":"Slowest individual calls"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["totals","endpoints","outliers","execution_time_ms"],"title":"FetchXhrResponse","description":"Response for the fetch_xhr dashboard panel: three blocks."},"FetchXhrTotals":{"properties":{"calls":{"type":"integer","title":"Calls","description":"Total fetch_xhr calls"},"errors":{"type":"integer","title":"Errors","description":"All fetch_xhr errors (status >= 400 or 0), both halves. Kept unchanged so nothing reading it shifts meaning."},"first_party_errors":{"type":"integer","title":"First Party Errors","description":"Errors on the site's own hosts, same-origin or a subdomain of the same registrable domain. The actionable half. Rows written before migration 073 have no split and count their whole error total here, the meaning they were collected under.","default":0},"third_party_errors":{"type":"integer","title":"Third Party Errors","description":"Errors on foreign hosts. Dominated by ad blockers and tracking protection, so not a defect of the site. 0 on rows written before migration 073.","default":0},"error_rate":{"type":"number","title":"Error Rate","description":"first_party_errors / calls (0 when no calls). Deliberately NOT the all-origin errors: a blocked tracker would otherwise read as the site failing."},"worst_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Worst Ms","description":"Slowest single observed call (ms)"}},"type":"object","required":["calls","errors","error_rate"],"title":"FetchXhrTotals","description":"Aggregate fetch_xhr counters across the queried scope.\n\nSplit by ownership since migration 073. A failure on a foreign host is not\nthe customer's bug in either direction: they cannot fix a vendor's outage\nand they cannot unblock a visitor's ad blocker. So `error_rate` counts the\nfirst-party half only, and the third-party half is reported beside it\nrather than folded in."},"FieldPoint":{"properties":{"ts":{"type":"string","title":"Ts"},"samples":{"type":"integer","title":"Samples"},"lcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp"},"fcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fcp"},"cls":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cls"},"inp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp"},"ttfb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ttfb"}},"type":"object","required":["ts","samples","lcp","fcp","cls","inp","ttfb"],"title":"FieldPoint","description":"One RUM bucket (regular). p75 per metric (ms; cls unitless)."},"Filters":{"properties":{"site_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id","description":"Filter by specific site"},"site_ids":{"anyOf":[{"items":{"type":"string","format":"uuid"},"type":"array","minItems":1},{"type":"null"}],"title":"Site Ids","description":"Filter by multiple sites (OR). Must be non-empty when present — an empty list is rejected with 422. Ignored when `site_id` is also set (precedence: site_id > site_ids > application_id > tags)."},"application_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Application Id","description":"Filter to every domain (site) of one application — the aggregated per-application scope. Resolved to the app's site_ids. Ignored when a higher-precedence site filter is set (precedence: site_id > site_ids > application_id > tags)."},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tags","description":"Filter by site tags (AND semantics)"},"browser":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Browser","description":"Filter by browsers"},"device_type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Device Type","description":"Filter by device types"},"os":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Os","description":"Filter by OS"},"country":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Country","description":"Filter by countries (ISO codes)"},"connection_type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Connection Type","description":"Filter by connection types"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"Filter by URL (supports * wildcards)"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain","description":"Filter by domain"},"referrer_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referrer Source","description":"Filter by referrer source bucket (e.g. Google, Direct)"},"referrer_medium":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Referrer Medium","description":"Filter by Snowplow referer-parser medium (search/social/email/paid/internal/unknown)"},"utm_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Source","description":"Filter by UTM source bucket (marketer-set, e.g. google, newsletter)"},"utm_medium":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Medium","description":"Filter by UTM medium (marketer-set, e.g. cpc, email, social)"},"utm_campaign":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Campaign","description":"Filter by UTM campaign identifier"},"utm_term":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Term","description":"Filter by UTM term (PPC keyword). High cardinality: useful for scoping a query, less so as a group-by dimension."},"utm_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Utm Content","description":"Filter by UTM content (A/B variant / ad creative ID). High cardinality: useful for A/B comparisons, less so as a group-by dimension."},"click_id_param":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Click Id Param","description":"Filter by ad-platform click-ID label (gclid/fbclid/msclkid/...)"},"nav_type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Nav Type","description":"Filter by navigation type (navigate/reload/back_forward/prerender/softnav)"},"protocol":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Protocol","description":"Filter by protocol (h2/h3/http1.1)"},"viewport_class":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Viewport Class","description":"Filter by viewport class (mobile/tablet/desktop/large)"},"dominant_third_party_category":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Dominant Third Party Category","description":"Filter by dominant third-party category (analytics/ads/tag-manager/...)"},"error_origin":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Error Origin","description":"Filter by error origin. Stored values: 'first' (the pageview carried an error on one of your own hosts), 'third' (it carried errors and every host seen was foreign), '' (no errors, or none whose origin could be determined - a frameless error such as a masked `Script error.` lands here)."},"cdn_cache_status":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Cdn Cache Status","description":"Filter by CDN cache status (HIT/MISS/EXPIRED/...). The empty string '' is a valid value and matches pageviews that reported no CDN cache status at all."},"origin_cache_status":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Origin Cache Status","description":"Filter by origin/FPC cache status (HIT/MISS/...). The empty string '' is a valid value and matches pageviews that reported no origin cache status at all."},"page_type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Page Type","description":"Filter by page type (product/category/cart/...)"},"origin_host":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Origin Host","description":"Filter by the origin node that served the pageview (from the `fm-host` Server-Timing key). The empty string '' is a valid value and matches pageviews that reported no host at all."},"logged_in":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Logged In","description":"Filter by authenticated-render state (from the `fm-loggedin` Server-Timing key): 'yes' / 'no', or '' for pageviews that reported nothing. Use it to separate the personalized traffic that bypasses the full-page cache from the cacheable anonymous traffic."},"checkout_stage":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Checkout Stage","description":"Filter by checkout-funnel stage of the pageview itself (cart/checkout/success). The empty string '' is a valid value and matches every pageview outside the funnel. Requires checkout_tracking on the application; deliberately NOT a slicing dimension, so a query filtering on it reads the pageview source rather than an aggregate tier."},"datacenter":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Datacenter","description":"Filter by datacenter/crawler network label (aws/hetzner/googlebot/...). The empty string '' is a valid value and matches normal (non-datacenter) traffic - e.g. exclude={'datacenter': ['']} keeps ONLY datacenter traffic, while datacenter=[''] keeps only residential traffic."},"bot_name":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Bot Name","description":"Filter by detected bot slug (googlebot/gptbot/...; the reserved 'unknown' = generic bot heuristics matched without a named entry). The empty string '' matches traffic with no bot signal - bot_name=[''] is the 'humans only' filter."},"bot_type":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Bot Type","description":"Filter by bot category tag (ai-crawler/search-engine/seo/monitoring/...). '' matches traffic with no bot signal."},"ua_anomaly":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Ua Anomaly","description":"Filter by UA consistency signal (headless/spoofed/non-browser). '' matches unremarkable traffic."},"bot_class":{"anyOf":[{"items":{"$ref":"#/components/schemas/BotClass"},"type":"array"},{"type":"null"}],"title":"Bot Class","description":"Derived traffic verdict filter - a three-way PARTITION (values always sum to all traffic): 'bot' = declared/verified bots (bot UA or published crawler IP range), 'suspect' = indications without declaration (UA/client-hints contradiction or hosting-datacenter IP), 'none' = no signal (humans). ['none'] is the 'real visitors' filter; multiple values are ORed."},"is_bot":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Bot","description":"Derived boolean filter: true = only detected bots (any bot_name incl. 'unknown'), false = humans only (no bot signal). Shorthand for bot_name != '' / = ''."},"is_datacenter":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Datacenter","description":"Derived boolean filter: true = only traffic from known hosting/crawler networks, false = residential networks only. Shorthand for datacenter != '' / = ''."},"pvid":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Pvid","description":"Filter by pageview ID(s) — e.g. to share / deep-link a specific beacon (all beacons of that pageview). Exact match (IN)."},"stitch":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Stitch","description":"Filter by stitch visitor ID(s) — the 32-hex edge-computed identity (`lower(hex(stitch))` as surfaced by /analytics/beacons). Exact match (IN). Values that aren't 32 lowercase-hex chars are dropped; an all-invalid filter matches nothing."},"tracker_version":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Tracker Version","description":"Filter by tracker bundle version (e.g. rollout debugging)"},"error_fingerprint":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Error Fingerprint","description":"Filter by error signature(s) — the `fingerprint` key returned by /analytics/error-types and /analytics/failed-resources. Narrows the traffic to the pageviews that carried one of these signatures, so any panel can be read over 'the pages where this breaks': LCP, browsers, countries, funnel. Say which population the key came from with `error_fingerprint_kind`. Reads the `errors` Nested column, which no rollup carries, so a query using it always reads source `beacons` and costs accordingly. Rejected by the endpoints that group BY fingerprint themselves (/analytics/error-types, /analytics/failed-resources and their /detail routes) — those name the signature in their own field."},"error_fingerprint_kind":{"anyOf":[{"$ref":"#/components/schemas/ErrorFingerprintKind"},{"type":"null"}],"description":"Which population `error_fingerprint` belongs to; unset means `error`, as on /analytics/beacons. Both halves of the `errors` column carry fingerprints out of one key space, so a resource signature scoped as an error matches nothing at all. Nullable rather than defaulted because it is a modifier of the field above: a default would put it in every `applied_filters` echo of every query that filters on nothing of the sort."},"metric_ranges":{"anyOf":[{"items":{"$ref":"#/components/schemas/MetricRange"},"type":"array"},{"type":"null"}],"title":"Metric Ranges","description":"Numeric threshold filters (gte/lte) on beacon metrics — e.g. {metric:'lcp', gte:2500} for slow-LCP pageviews, or {metric:'error_count', gte:1} for pageviews with errors. Also carries the browser MAJOR version: {metric:'browser_version', gte:150} = 'browser >= 150' (pair with a `browser` family filter for 'Chrome >= 150'). Multiple are ANDed."},"exclude":{"anyOf":[{"additionalProperties":{"items":{"type":"string"},"type":"array"},"propertyNames":{"$ref":"#/components/schemas/ExcludeColumn"},"type":"object"},{"type":"null"}],"title":"Exclude","description":"Negative filters: column → values to EXCLUDE (NOT IN). Keys are the allowlisted categorical columns (see the ExcludeColumn enum in the schema). e.g. {'country': ['DE','NL']} drops DE+NL; multiple columns are ANDed. Complements the positive (IN) filters above.","examples":[{"country":["DE","NL"]}]}},"additionalProperties":false,"type":"object","title":"Filters","description":"Query filters for narrowing down results."},"FunnelBucket":{"properties":{"bucket":{"type":"string","format":"date-time","title":"Bucket"},"reached":{"additionalProperties":{"type":"integer"},"type":"object","title":"Reached","description":"Step name -> visitors who entered in this bucket and reached that step"},"cart_interactions":{"type":"integer","title":"Cart Interactions","description":"Visitors who entered in this bucket and whose session issued at least one cart interaction (fetch/XHR cart mutation: add, change or remove - the kinds are not separable). Reported beside the steps, not as one: its coverage depends on collect_fetch_xhr and the shop system, so it would be a misleading conversion baseline.","default":0}},"type":"object","required":["bucket","reached"],"title":"FunnelBucket","description":"One time bucket of the funnel series.\n\nA visitor is counted in the bucket of their funnel ENTRY (their first\npageview at any step), never in the bucket of their success. That makes a\nday finally computable once the day plus the 24h stitch window plus the\nfinalizer lag have passed, instead of shifting as late successes arrive."},"FunnelStep":{"properties":{"name":{"type":"string","title":"Name","description":"Step name (checkout funnel: cart | checkout | success)"},"reached":{"type":"integer","title":"Reached","description":"Visitors who reached this step at least once"},"conversion_rate":{"type":"number","title":"Conversion Rate","description":"Share of the FIRST step's visitors that reached this step. 1.0 on the first step; 0.0 when the first step has no visitors. Can exceed 1.0: a visitor can enter a later step without the first one being observed (deep link into the checkout, drawer cart with no URL, express checkout), which is real behaviour and not normalized away - render accordingly."},"step_conversion_rate":{"type":"number","title":"Step Conversion Rate","description":"Share of the PREVIOUS step's visitors that reached this step (0..1). Can exceed 1.0: a visitor may enter a later step without the earlier one being observed (deep link into the checkout, cart page never loaded), which is real behaviour and not normalized away."}},"type":"object","required":["name","reached","conversion_rate","step_conversion_rate"],"title":"FunnelStep","description":"One step of a funnel over the whole reported window."},"GateCheckResponse":{"properties":{"name":{"type":"string","title":"Name"},"value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Value"},"threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Threshold"},"op":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Op"},"passed":{"type":"boolean","title":"Passed"},"waived":{"type":"boolean","title":"Waived","default":false},"internal":{"type":"boolean","title":"Internal","default":false}},"type":"object","required":["name","passed"],"title":"GateCheckResponse","description":"One recorded condition of the gate protocol: what was measured, what\nwas required, and whether it held. `waived` marks a condition that passed\nby rule rather than by number (the total-outage escape hatch, the\nwas-perfect-now-is-not ratio). `internal` conditions carry engine\nvocabulary and only appear for admins with `include_stats`."},"GateResultResponse":{"properties":{"key":{"type":"string","title":"Key"},"label":{"type":"string","title":"Label"},"passed":{"type":"boolean","title":"Passed"},"checks":{"items":{"$ref":"#/components/schemas/GateCheckResponse"},"type":"array","title":"Checks"}},"type":"object","required":["key","label","passed"],"title":"GateResultResponse"},"Granularity":{"type":"string","enum":["none","minute","hour","day","week","month"],"title":"Granularity","description":"Time bucketing granularity for GROUP BY."},"GroupBy":{"properties":{"granularity":{"$ref":"#/components/schemas/Granularity","description":"Time bucket granularity for grouping","default":"none"},"dimensions":{"items":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/MapDimension"}]},"type":"array","maxItems":2,"title":"Dimensions","description":"Dimensions to group by (max 2). Strings for flat or Nested (errors.*) columns; objects for Map columns."}},"type":"object","title":"GroupBy","description":"Grouping configuration for queries."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HighlightResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"application_id":{"type":"string","format":"uuid","title":"Application Id"},"detector_key":{"type":"string","title":"Detector Key"},"is_shadow":{"type":"boolean","title":"Is Shadow"},"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"evidence":{"additionalProperties":true,"type":"object","title":"Evidence"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","organization_id","application_id","detector_key","is_shadow","title","summary","evidence","created_at"],"title":"HighlightResponse"},"HistogramBucket":{"properties":{"bucket":{"type":"string","title":"Bucket","description":"Bucket label (e.g., '0-500ms')"},"min_value":{"type":"number","title":"Min Value","description":"Minimum value for this bucket (inclusive)"},"max_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Value","description":"Maximum value for this bucket (exclusive, None for last bucket)"},"count":{"type":"integer","title":"Count","description":"Number of samples in this bucket"},"percentage":{"type":"number","title":"Percentage","description":"Percentage of total samples"}},"type":"object","required":["bucket","min_value","max_value","count","percentage"],"title":"HistogramBucket","description":"Single bucket in a histogram."},"HistogramMeta":{"properties":{"total_samples":{"type":"integer","title":"Total Samples","description":"Total samples in histogram"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time in milliseconds"},"metric":{"type":"string","title":"Metric","description":"Metric used for histogram"},"time_range":{"additionalProperties":true,"type":"object","title":"Time Range","description":"Applied time range"},"applied_filters":{"additionalProperties":true,"type":"object","title":"Applied Filters","description":"Applied filter values"}},"type":"object","required":["total_samples","execution_time_ms","metric","time_range","applied_filters"],"title":"HistogramMeta","description":"Metadata about histogram query execution."},"HistogramRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query (required)"},"metric":{"type":"string","title":"Metric","description":"Metric to create histogram for (e.g., lcp, ttfb)"},"buckets":{"items":{"type":"number"},"type":"array","maxItems":20,"minItems":2,"title":"Buckets","description":"Bucket boundaries (e.g., [0, 500, 1000, 2500, 4000] creates 5 buckets)"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"}},"additionalProperties":false,"type":"object","required":["time_range","metric","buckets"],"title":"HistogramRequest","description":"Request schema for histogram queries."},"HistogramResponse":{"properties":{"buckets":{"items":{"$ref":"#/components/schemas/HistogramBucket"},"type":"array","title":"Buckets","description":"Histogram buckets with counts"},"meta":{"$ref":"#/components/schemas/HistogramMeta","description":"Query metadata"}},"type":"object","required":["buckets","meta"],"title":"HistogramResponse","description":"Response for histogram queries."},"InviteCreate":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"role":{"$ref":"#/components/schemas/Role","default":"member"}},"type":"object","required":["email"],"title":"InviteCreate"},"InviteResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"$ref":"#/components/schemas/Role"},"invited_by_id":{"type":"string","format":"uuid","title":"Invited By Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"}},"type":"object","required":["id","email","role","invited_by_id","created_at","expires_at"],"title":"InviteResponse"},"IssueActor":{"type":"string","enum":["system","user","ai"],"title":"IssueActor"},"IssueCategory":{"type":"string","enum":["web_vitals","errors","traffic","fetch"],"title":"IssueCategory"},"IssueComment":{"properties":{"comment":{"type":"string","maxLength":2000,"minLength":1,"title":"Comment"}},"type":"object","required":["comment"],"title":"IssueComment"},"IssueDetailResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"application_id":{"type":"string","format":"uuid","title":"Application Id"},"site_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id"},"detector_key":{"type":"string","title":"Detector Key"},"fingerprint":{"type":"string","title":"Fingerprint"},"category":{"$ref":"#/components/schemas/IssueCategory"},"severity":{"$ref":"#/components/schemas/IssueSeverity"},"status":{"$ref":"#/components/schemas/IssueStatus"},"is_shadow":{"type":"boolean","title":"Is Shadow"},"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"evidence":{"additionalProperties":true,"type":"object","title":"Evidence"},"first_seen_at":{"type":"string","format":"date-time","title":"First Seen At"},"last_seen_at":{"type":"string","format":"date-time","title":"Last Seen At"},"opened_at":{"type":"string","format":"date-time","title":"Opened At"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"muted_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Muted Until"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"events":{"items":{"$ref":"#/components/schemas/IssueEventResponse"},"type":"array","title":"Events"}},"type":"object","required":["id","organization_id","application_id","detector_key","fingerprint","category","severity","status","is_shadow","title","summary","evidence","first_seen_at","last_seen_at","opened_at","created_at","updated_at"],"title":"IssueDetailResponse"},"IssueEventResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"$ref":"#/components/schemas/IssueEventType"},"actor":{"$ref":"#/components/schemas/IssueActor"},"actor_user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Actor User Id"},"value_snapshot":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Value Snapshot"},"comment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Comment"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","type","actor","created_at"],"title":"IssueEventResponse"},"IssueEventType":{"type":"string","enum":["opened","updated","escalated","resolved","regressed","muted","unmuted","comment"],"title":"IssueEventType"},"IssueExplanationResponse":{"properties":{"issue_id":{"type":"string","format":"uuid","title":"Issue Id"},"detector_key":{"type":"string","title":"Detector Key"},"metric":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Metric"},"status":{"$ref":"#/components/schemas/IssueStatus"},"severity":{"$ref":"#/components/schemas/IssueSeverity"},"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"window_hours":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Window Hours"},"baseline":{"additionalProperties":true,"type":"object","title":"Baseline"},"observed":{"additionalProperties":true,"type":"object","title":"Observed"},"gates":{"anyOf":[{"items":{"$ref":"#/components/schemas/GateResultResponse"},"type":"array"},{"type":"null"}],"title":"Gates"},"diagnosis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Diagnosis"},"peak_delta_pp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Peak Delta Pp"},"last_evaluated_at":{"type":"string","format":"date-time","title":"Last Evaluated At"}},"type":"object","required":["issue_id","detector_key","status","severity","title","summary","baseline","observed","last_evaluated_at"],"title":"IssueExplanationResponse","description":"Why this issue exists: the gate protocol recorded at evaluation time.\n\nRecorded, not reconstructed: gate thresholds are code constants and get\nretuned, so recomputing them at read time could claim an old issue passed\ngates it never saw. `gates` is None for issues that predate the protocol."},"IssueResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"application_id":{"type":"string","format":"uuid","title":"Application Id"},"site_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id"},"detector_key":{"type":"string","title":"Detector Key"},"fingerprint":{"type":"string","title":"Fingerprint"},"category":{"$ref":"#/components/schemas/IssueCategory"},"severity":{"$ref":"#/components/schemas/IssueSeverity"},"status":{"$ref":"#/components/schemas/IssueStatus"},"is_shadow":{"type":"boolean","title":"Is Shadow"},"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"evidence":{"additionalProperties":true,"type":"object","title":"Evidence"},"first_seen_at":{"type":"string","format":"date-time","title":"First Seen At"},"last_seen_at":{"type":"string","format":"date-time","title":"Last Seen At"},"opened_at":{"type":"string","format":"date-time","title":"Opened At"},"resolved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Resolved At"},"muted_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Muted Until"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","organization_id","application_id","detector_key","fingerprint","category","severity","status","is_shadow","title","summary","evidence","first_seen_at","last_seen_at","opened_at","created_at","updated_at"],"title":"IssueResponse"},"IssueSeverity":{"type":"string","enum":["low","medium","high"],"title":"IssueSeverity"},"IssueStatus":{"type":"string","enum":["open","resolved","muted","regressed"],"title":"IssueStatus"},"IssueUpdate":{"properties":{"status":{"anyOf":[{"$ref":"#/components/schemas/IssueStatus"},{"type":"null"}]},"mute_until":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Mute Until"}},"type":"object","title":"IssueUpdate","description":"Triage actions. Exactly one of these is meaningful per call.\n\n`mute_until` implements the plan's archive-until semantics: it pauses\nNOTIFICATION, never detection — the engine keeps tracking the slice, so the\ntimeline stays complete and an escalation can still be recognised."},"LabPoint":{"properties":{"ts":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ts"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score"},"lcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp"},"fcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fcp"},"cls":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cls"},"inp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp"},"ttfb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ttfb"}},"type":"object","required":["ts","score","lcp","fcp","cls","inp","ttfb"],"title":"LabPoint","description":"One CS analysis run (sparse). Score is the CS sum; CWV are ms (cls unitless),\nparsed from that run's scores[]."},"LabVsFieldResponse":{"properties":{"page_id":{"type":"string","format":"uuid","title":"Page Id"},"url":{"type":"string","title":"Url"},"window_days":{"type":"integer","title":"Window Days"},"devices":{"items":{"$ref":"#/components/schemas/DeviceComparison"},"type":"array","title":"Devices"}},"type":"object","required":["page_id","url","window_days","devices"],"title":"LabVsFieldResponse"},"LighthouseOpportunity":{"properties":{"id":{"type":"string","title":"Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score"},"savings_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Savings Ms"}},"type":"object","required":["id","title","score","savings_ms"],"title":"LighthouseOpportunity"},"LighthouseReportResponse":{"properties":{"page_id":{"type":"string","format":"uuid","title":"Page Id"},"device":{"type":"string","title":"Device"},"lighthouse_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lighthouse Version"},"fetched_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Fetched Url"},"categories":{"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]},"type":"object","title":"Categories"},"metrics":{"additionalProperties":{"anyOf":[{"type":"number"},{"type":"null"}]},"type":"object","title":"Metrics"},"opportunities":{"items":{"$ref":"#/components/schemas/LighthouseOpportunity"},"type":"array","title":"Opportunities"},"audits":{"additionalProperties":true,"type":"object","title":"Audits"}},"type":"object","required":["page_id","device","lighthouse_version","fetched_url","categories","metrics","opportunities","audits"],"title":"LighthouseReportResponse","description":"Curated Lighthouse report: category scores, metrics (ms), opportunities, and\na whitelist of native Lighthouse audit objects (waterfall / third-party /\nresource-summary / filmstrip / main-thread) for the frontend to render."},"LighthouseSummaryResponse":{"properties":{"page_id":{"type":"string","format":"uuid","title":"Page Id"},"analysis_uuid":{"type":"string","title":"Analysis Uuid"},"device":{"type":"string","title":"Device"},"language":{"type":"string","title":"Language"},"summary":{"type":"string","title":"Summary"},"cached":{"type":"boolean","title":"Cached"}},"type":"object","required":["page_id","analysis_uuid","device","language","summary","cached"],"title":"LighthouseSummaryResponse","description":"AI-generated summary of a Lighthouse run (one device + language). Persisted and\nreused — `cached=false` means it was generated on this request."},"LoAFItem":{"properties":{"duration":{"type":"number","title":"Duration","description":"Frame duration in ms"},"script_url":{"type":"string","title":"Script Url","description":"Primary script URL"},"count":{"type":"integer","title":"Count","description":"Number of occurrences"}},"type":"object","required":["duration","script_url","count"],"title":"LoAFItem","description":"Single long animation frame."},"LoAFRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","description":"Max LoAF entries to return","default":10}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"LoAFRequest","description":"Request for Long Animation Frames data."},"LoAFResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/LoAFItem"},"type":"array","title":"Data","description":"Long animation frames"},"total_frames":{"type":"integer","title":"Total Frames","description":"Total long frames"},"avg_duration":{"type":"number","title":"Avg Duration","description":"Average frame duration"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["data","total_frames","avg_duration","execution_time_ms"],"title":"LoAFResponse","description":"Response for Long Animation Frames data."},"MapDimension":{"properties":{"map":{"type":"string","title":"Map","description":"Map column name (e.g. 'third_parties')"}},"additionalProperties":false,"type":"object","required":["map"],"title":"MapDimension","description":"Group by the keys of a Map column (ARRAY JOIN mapKeys / mapValues).\n\nExample: `{\"map\": \"third_parties\"}` produces one row per (beacon, domain)\nwith `third_parties_key` (the domain) as the dimension and an\nauto-emitted `<map>_total` metric (sum of map values across the group)."},"MapMetric":{"properties":{"map":{"type":"string","title":"Map","description":"Map column name (e.g. 'resource_sizes')"},"key":{"type":"string","maxLength":128,"minLength":1,"pattern":"^[a-zA-Z0-9._-]+$","title":"Key","description":"Map key to extract. Restricted to [a-zA-Z0-9._-] to keep the bracket expression SQL-safe; covers resource types, category names, and sanitized hostnames."}},"additionalProperties":false,"type":"object","required":["map","key"],"title":"MapMetric","description":"Aggregate a single key from a Map column. Behaves like a flat metric:\nthe request's `aggregations` list (sum / avg / p75 / …) is applied to\n`<map>['<key>']` directly, no ARRAY JOIN required.\n\nExample: `{\"map\": \"resource_sizes\", \"key\": \"script\"}` aggregates the\nper-beacon `resource_sizes['script']` value."},"MemberAdd":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"role":{"$ref":"#/components/schemas/Role","default":"member"}},"type":"object","required":["email"],"title":"MemberAdd"},"MemberResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"email":{"type":"string","title":"Email"},"full_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Name"},"role":{"$ref":"#/components/schemas/Role"},"totp_enabled":{"type":"boolean","title":"Totp Enabled","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","user_id","email","full_name","role","created_at"],"title":"MemberResponse"},"MemberRoleUpdate":{"properties":{"role":{"$ref":"#/components/schemas/Role"}},"type":"object","required":["role"],"title":"MemberRoleUpdate"},"Message":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"Message"},"MetadataResponse":{"properties":{"metrics":{"items":{"$ref":"#/components/schemas/MetricMeta"},"type":"array","title":"Metrics"},"aggregations":{"items":{"type":"string"},"type":"array","title":"Aggregations"},"dimensions":{"items":{"type":"string"},"type":"array","title":"Dimensions"},"window_options_seconds":{"items":{"type":"integer"},"type":"array","title":"Window Options Seconds"}},"type":"object","required":["metrics","aggregations","dimensions","window_options_seconds"],"title":"MetadataResponse"},"MetricComparison":{"properties":{"metric":{"type":"string","title":"Metric"},"lab_value":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lab Value"},"field_p75":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Field P75"},"verdict":{"type":"string","title":"Verdict"}},"type":"object","required":["metric","lab_value","field_p75","verdict"],"title":"MetricComparison","description":"One CWV metric, lab (CS) vs field (RUM p75), in canonical ms (cls unitless)."},"MetricMeta":{"properties":{"name":{"type":"string","title":"Name"},"label":{"type":"string","title":"Label"},"unit":{"anyOf":[{"type":"string","enum":["ms","s","score","count","bytes","rate","percent"]},{"type":"null"}],"title":"Unit"},"supported_aggregations":{"items":{"type":"string"},"type":"array","title":"Supported Aggregations"}},"type":"object","required":["name","label","supported_aggregations"],"title":"MetricMeta"},"MetricRange":{"properties":{"metric":{"type":"string","title":"Metric","description":"Metric column — allowlisted (lcp/inp/cls/error_count/…)"},"gte":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Gte","description":"Keep rows with metric >= this"},"lte":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lte","description":"Keep rows with metric <= this"}},"additionalProperties":false,"type":"object","required":["metric"],"title":"MetricRange","description":"A numeric threshold filter on ONE beacon metric (e.g. `{metric:'lcp', gte:2500}`\nfor slow-LCP pageviews, or `{metric:'error_count', gte:1}` = \"has errors\").\nAt least one bound required. NULL metric values don't match (a softnav with no\nLCP isn't a \"slow-LCP\" pageview) — true for the Nullable columns. Note:\n`fetch_xhr_total_calls`/`_total_errors` are non-nullable (0-default), so an\n`lte` on those matches genuine-zero rows."},"MetricValue":{"properties":{"metric":{"type":"string","title":"Metric","description":"Metric name"},"aggregation":{"$ref":"#/components/schemas/AggregationType","description":"Aggregation type"},"value":{"anyOf":[{"type":"number"},{"type":"integer"},{"type":"null"}],"title":"Value","description":"Aggregated value"}},"type":"object","required":["metric","aggregation","value"],"title":"MetricValue","description":"Single metric with its aggregation result."},"Operator":{"type":"string","enum":["gt","gte","lt","lte"],"title":"Operator"},"OrderBy":{"properties":{"field":{"type":"string","title":"Field","description":"Field to sort by (metric name or dimension)"},"direction":{"$ref":"#/components/schemas/SortDirection","description":"Sort direction","default":"desc"}},"type":"object","required":["field"],"title":"OrderBy","description":"Sort configuration for results."},"OrgKeyCreate":{"properties":{"current_password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Password"},"totp_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Totp Code"},"passkey_challenge_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Passkey Challenge Id"},"passkey_assertion":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Passkey Assertion"},"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"},"audience":{"type":"string","enum":["own","clients"],"title":"Audience","default":"own"},"scopes":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Scopes"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["name","scopes","expires_at"],"title":"OrgKeyCreate","description":"Mint an org key. The step-up fields re-authenticate the acting human -\nthe key itself belongs to nobody and never authenticates interactively."},"OrgKeyUpdate":{"properties":{"current_password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Password"},"totp_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Totp Code"},"passkey_challenge_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Passkey Challenge Id"},"passkey_assertion":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Passkey Assertion"},"name":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"Name"},"scopes":{"anyOf":[{"items":{"type":"string"},"type":"array","minItems":1},{"type":"null"}],"title":"Scopes"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"}},"type":"object","title":"OrgKeyUpdate","description":"Rename an org key, change its scopes, or both. Same contract as\n`ApiKeyUpdate`, minus the reach question - an org key names one\norganization by construction, so there was never a list to edit."},"OrgSiteStatusItem":{"properties":{"beacons_today":{"type":"integer","title":"Beacons Today"},"beacons_per_minute":{"type":"number","title":"Beacons Per Minute"},"last_beacon_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Beacon At"},"site_id":{"type":"string","format":"uuid","title":"Site Id"}},"type":"object","required":["beacons_today","beacons_per_minute","site_id"],"title":"OrgSiteStatusItem","description":"One site's beacon status within the org-wide status listing.\n\nSame fields as `SiteStatusResponse` plus the `site_id` the row belongs to,\nso a single call can back the dashboard header widget across every site."},"OrganizationCreate":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name"},"intended_domain":{"type":"string","title":"Intended Domain"}},"type":"object","required":["name","intended_domain"],"title":"OrganizationCreate"},"OrganizationHit":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"role":{"anyOf":[{"$ref":"#/components/schemas/Role"},{"type":"null"}]},"access":{"anyOf":[{"type":"string","enum":["member","partner","admin"]},{"type":"null"}],"title":"Access"},"is_partner":{"type":"boolean","title":"Is Partner"}},"type":"object","required":["id","name","is_partner"],"title":"OrganizationHit","description":"An organization as a hit in its own right.\n\nInherits the reference shape so the \"both omitted for an ownerless\ncredential\" rule is stated once and cannot drift between the two places an\norganization appears in a response."},"OrganizationResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"is_active":{"type":"boolean","title":"Is Active"},"review_status":{"$ref":"#/components/schemas/ReviewStatus"},"intended_domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Intended Domain"},"storage":{"$ref":"#/components/schemas/Storage"},"clickhouse_table":{"type":"string","title":"Clickhouse Table"},"plan":{"$ref":"#/components/schemas/Plan"},"is_partner":{"type":"boolean","title":"Is Partner"},"ai_enabled":{"type":"boolean","title":"Ai Enabled"},"synthetic_enabled":{"type":"boolean","title":"Synthetic Enabled"},"mcp_enabled":{"type":"boolean","title":"Mcp Enabled"},"role":{"anyOf":[{"$ref":"#/components/schemas/Role"},{"type":"null"}]},"permissions":{"items":{"type":"string"},"type":"array","title":"Permissions","default":[]},"access":{"anyOf":[{"type":"string","enum":["member","partner","admin"]},{"type":"null"}],"title":"Access"}},"type":"object","required":["id","name","is_active","review_status","storage","clickhouse_table","plan","is_partner","ai_enabled","synthetic_enabled","mcp_enabled"],"title":"OrganizationResponse"},"OrganizationUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":128,"minLength":1},{"type":"null"}],"title":"Name"},"ai_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ai Enabled"},"synthetic_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Synthetic Enabled"},"mcp_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Mcp Enabled"}},"type":"object","title":"OrganizationUpdate"},"OwnershipTransferRequest":{"properties":{"new_owner_user_id":{"type":"string","format":"uuid","title":"New Owner User Id"}},"type":"object","required":["new_owner_user_id"],"title":"OwnershipTransferRequest"},"PageSparkline":{"properties":{"page_id":{"type":"string","format":"uuid","title":"Page Id"},"url":{"type":"string","title":"Url"},"run_count":{"type":"integer","title":"Run Count"},"latest_desktop_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latest Desktop Score"},"latest_mobile_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Latest Mobile Score"},"series":{"items":{"$ref":"#/components/schemas/SparklinePoint"},"type":"array","title":"Series"}},"type":"object","required":["page_id","url","run_count","latest_desktop_score","latest_mobile_score","series"],"title":"PageSparkline","description":"A page's overview: total run count + recent per-run scores for a mini graph,\nplus its latest score per device. Built live from the 1h-cached series."},"PageTypeDetectionResponse":{"properties":{"url":{"type":"string","title":"Url","description":"The page that was probed."},"final_url":{"type":"string","title":"Final Url","description":"Where it ended up after redirects.","default":""},"status":{"type":"integer","title":"Status","description":"HTTP status the probe saw.","default":0},"detected_ruleset":{"type":"string","title":"Detected Ruleset","description":"Inferred shop system, '' when nothing was recognised. May name a system that is not a selectable ruleset, e.g. 'shopify'.","default":""},"ruleset_supported":{"type":"boolean","title":"Ruleset Supported","description":"Whether `detected_ruleset` is a valid `pagetype_ruleset` value.","default":false},"matched_via":{"type":"string","title":"Matched Via","description":"Evidence: 'header:x-shopid', 'body_class:is-ctl-navigation', 'generator:…'.","default":""},"page_type":{"type":"string","title":"Page Type","description":"page_type of the probed page under the detected ruleset. The home page, so 'home' is the expected answer and anything else is a hint that the theme renames classes.","default":""},"body_classes":{"items":{"type":"string"},"type":"array","title":"Body Classes","description":"Classes found on the page's `<body>`."},"generators":{"items":{"type":"string"},"type":"array","title":"Generators","description":"`<meta name=\"generator\">` values."}},"type":"object","required":["url"],"title":"PageTypeDetectionResponse","description":"What a shop-system probe found on the application's own home page.\n\nDetection only. Nothing is written: the caller decides whether to PATCH\n`pagetype_ruleset` with `detected_ruleset`, and may only do so when\n`ruleset_supported` is true."},"PageTypeDiscoverCandidate":{"properties":{"page_type":{"type":"string","title":"Page Type"},"body_classes":{"items":{"type":"string"},"type":"array","title":"Body Classes","description":"Classes on every page of this type and on no other page read."}},"type":"object","required":["page_type"],"title":"PageTypeDiscoverCandidate","description":"The classes that would identify one page type, and how sure that is."},"PageTypeDiscoverPage":{"properties":{"url":{"type":"string","maxLength":2048,"title":"Url","description":"Absolute https URL on one of the application's own domains."},"page_type":{"type":"string","title":"Page Type","description":"What this page is, from the fixed page-type enum."}},"type":"object","required":["url","page_type"],"title":"PageTypeDiscoverPage","description":"One page the customer labelled: where it is and what kind of page it is."},"PageTypeDiscoverPageResult":{"properties":{"url":{"type":"string","title":"Url"},"page_type":{"type":"string","title":"Page Type","description":"Empty on the baseline page, which carries no label.","default":""},"read":{"type":"boolean","title":"Read","description":"False when the page could not be fetched in time."},"status":{"type":"integer","title":"Status","description":"HTTP status of the fetch, 0 when it never happened.","default":0},"body_classes":{"items":{"type":"string"},"type":"array","title":"Body Classes"}},"type":"object","required":["url","read"],"title":"PageTypeDiscoverPageResult","description":"What reading one page produced."},"PageTypeDiscoverRequest":{"properties":{"pages":{"items":{"$ref":"#/components/schemas/PageTypeDiscoverPage"},"type":"array","maxItems":4,"minItems":1,"title":"Pages"}},"additionalProperties":false,"type":"object","required":["pages"],"title":"PageTypeDiscoverRequest","description":"Ask for rule proposals from a handful of labelled pages.\n\nEvery URL has to sit on a domain of this application. The endpoint makes the\nserver fetch what it is given, so the customer's own domains are the whole\ntarget set; only the path is theirs to choose."},"PageTypeDiscoverResponse":{"properties":{"rules":{"items":{"$ref":"#/components/schemas/PageTypeRule"},"type":"array","title":"Rules","description":"The confident subset, ready to PATCH as `pagetype_rules`: one page type, exactly one class. A type with several candidates or none is left out and appears under `candidates` instead."},"candidates":{"items":{"$ref":"#/components/schemas/PageTypeDiscoverCandidate"},"type":"array","title":"Candidates","description":"Every labelled page type and what was found for it."},"pages":{"items":{"$ref":"#/components/schemas/PageTypeDiscoverPageResult"},"type":"array","title":"Pages","description":"Every page read, the baseline included."}},"type":"object","title":"PageTypeDiscoverResponse","description":"Proposals only. Writing them is a separate PATCH the customer confirms."},"PageTypeRule":{"properties":{"body_class":{"type":"string","title":"Body Class"},"page_type":{"type":"string","title":"Page Type"}},"type":"object","required":["body_class","page_type"],"title":"PageTypeRule","description":"One customer-defined body class and the page type it stands for."},"PaginatedResponse_ApiKeyInfo_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ApiKeyInfo"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[ApiKeyInfo]"},"PaginatedResponse_ApplicationResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ApplicationResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[ApplicationResponse]"},"PaginatedResponse_AuditLogEntry_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/AuditLogEntry"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[AuditLogEntry]"},"PaginatedResponse_ConnectionInfo_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ConnectionInfo"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[ConnectionInfo]"},"PaginatedResponse_HighlightResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/HighlightResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[HighlightResponse]"},"PaginatedResponse_InviteResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/InviteResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[InviteResponse]"},"PaginatedResponse_IssueResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/IssueResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[IssueResponse]"},"PaginatedResponse_MemberResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/MemberResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[MemberResponse]"},"PaginatedResponse_OrganizationResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/OrganizationResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[OrganizationResponse]"},"PaginatedResponse_PartnerAccessResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/PartnerAccessResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[PartnerAccessResponse]"},"PaginatedResponse_PartnerClientResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/PartnerClientResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[PartnerClientResponse]"},"PaginatedResponse_ReleaseResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ReleaseResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[ReleaseResponse]"},"PaginatedResponse_RuleResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/RuleResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[RuleResponse]"},"PaginatedResponse_SendResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SendResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[SendResponse]"},"PaginatedResponse_SiteResponse_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SiteResponse"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[SiteResponse]"},"PaginatedResponse_SyntheticPageListItem_":{"properties":{"data":{"items":{"$ref":"#/components/schemas/SyntheticPageListItem"},"type":"array","title":"Data"},"meta":{"$ref":"#/components/schemas/PaginationMeta"}},"type":"object","required":["data","meta"],"title":"PaginatedResponse[SyntheticPageListItem]"},"PaginationMeta":{"properties":{"total":{"type":"integer","title":"Total"},"limit":{"type":"integer","title":"Limit"},"offset":{"type":"integer","title":"Offset"},"has_more":{"type":"boolean","title":"Has More"}},"type":"object","required":["total","limit","offset","has_more"],"title":"PaginationMeta"},"PartnerAccessResponse":{"properties":{"partner_org_id":{"type":"string","format":"uuid","title":"Partner Org Id"},"partner_org_name":{"type":"string","title":"Partner Org Name"},"billing":{"type":"boolean","title":"Billing"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["partner_org_id","partner_org_name","billing","created_at"],"title":"PartnerAccessResponse","description":"A partner organization that has access to this (client) org.\n\nThe client-side view of the `partners` relationship — \"who manages us\" —\nas opposed to PartnerClientResponse, which is the partner's view of \"our\nclients\". Lets a client org see, and decide to revoke, the partner access\ngranted over it."},"PartnerClientCreate":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name","description":"Name of the new client organization"},"billing":{"type":"boolean","title":"Billing","description":"Whether this partner handles billing","default":false},"owner_email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Owner Email","description":"Optional: invite this email as OWNER of the new client org. Sends an invite email; on accept the customer takes ownership. Omit to keep the org partner-managed (headless)."}},"additionalProperties":false,"type":"object","required":["name"],"title":"PartnerClientCreate","description":"Create a new organization and link it to this partner as a client.\n\nSelf-service counterpart to the admin-only link endpoint\n(`POST /admin/partners`, which attaches an *existing* org)."},"PartnerClientResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"partner_org_id":{"type":"string","format":"uuid","title":"Partner Org Id"},"client_org_id":{"type":"string","format":"uuid","title":"Client Org Id"},"client_org_name":{"type":"string","title":"Client Org Name"},"billing":{"type":"boolean","title":"Billing"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","partner_org_id","client_org_id","client_org_name","billing","created_at"],"title":"PartnerClientResponse","description":"A partner-client relationship."},"PartnerClientUsage":{"properties":{"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"type":"string","title":"Org Name"},"beacons":{"type":"integer","title":"Beacons"}},"type":"object","required":["org_id","org_name","beacons"],"title":"PartnerClientUsage","description":"Usage for a single client org."},"PartnerUsageResponse":{"properties":{"total_beacons":{"type":"integer","title":"Total Beacons"},"period_start":{"type":"string","format":"date-time","title":"Period Start"},"period_end":{"type":"string","format":"date-time","title":"Period End"},"clients":{"items":{"$ref":"#/components/schemas/PartnerClientUsage"},"type":"array","title":"Clients"}},"type":"object","required":["total_beacons","period_start","period_end","clients"],"title":"PartnerUsageResponse","description":"Aggregated usage across all partner clients."},"Plan":{"type":"string","enum":["none","beta","light","standard","partner","enterprise"],"title":"Plan","description":"Subscription plan for organization.\n\nNONE is the starting state and means exactly what it says: nobody has chosen\nanything yet. It used to be LIGHT, which showed a brand-new organization a\ntariff it never picked and conflated two different questions — \"what did the\ncustomer buy\" and \"what feature level applies\". An org leaves NONE by exactly\nthree routes: an approval starts its trial, a checkout buys a plan, or a\npartner provisions it."},"PresetActionTemplate":{"properties":{"type":{"$ref":"#/components/schemas/ActionType"},"config":{"additionalProperties":true,"type":"object","title":"Config"}},"type":"object","required":["type","config"],"title":"PresetActionTemplate"},"PresetResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"rule":{"additionalProperties":true,"type":"object","title":"Rule"},"default_actions":{"items":{"$ref":"#/components/schemas/PresetActionTemplate"},"type":"array","title":"Default Actions"}},"type":"object","required":["id","name","description","rule","default_actions"],"title":"PresetResponse"},"ReleaseCreate":{"properties":{"version":{"type":"string","maxLength":255,"title":"Version"},"released_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Released At"}},"additionalProperties":false,"type":"object","required":["version"],"title":"ReleaseCreate"},"ReleaseResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"application_id":{"type":"string","format":"uuid","title":"Application Id"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"version":{"type":"string","title":"Version"},"released_at":{"type":"string","format":"date-time","title":"Released At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","application_id","organization_id","version","released_at","created_at"],"title":"ReleaseResponse"},"ReleaseUpdate":{"properties":{"version":{"anyOf":[{"type":"string","maxLength":255},{"type":"null"}],"title":"Version"},"released_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Released At"}},"additionalProperties":false,"type":"object","title":"ReleaseUpdate"},"ResourceBreakdownRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"ResourceBreakdownRequest","description":"Request for resource breakdown by type."},"ResourceBreakdownResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ResourceTypeItem"},"type":"array","title":"Data","description":"Resource types with data"},"total_size":{"type":"integer","title":"Total Size","description":"Total size across all types"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["data","total_size","execution_time_ms"],"title":"ResourceBreakdownResponse","description":"Response for resource breakdown."},"ResourceTypeItem":{"properties":{"resource_type":{"type":"string","title":"Resource Type","description":"Resource type (script, css, img, font, other)"},"total_size":{"type":"integer","title":"Total Size","description":"Total size in bytes"},"total_count":{"type":"integer","title":"Total Count","description":"Total resource count"},"avg_duration":{"type":"number","title":"Avg Duration","description":"Average duration in ms"},"percentage":{"type":"number","title":"Percentage","description":"Percentage of total size"}},"type":"object","required":["resource_type","total_size","total_count","avg_duration","percentage"],"title":"ResourceTypeItem","description":"Single resource type with aggregated data."},"ResultDevice":{"properties":{"average":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Average"},"error":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Error"},"vitals":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Vitals"},"pages":{"additionalProperties":{"$ref":"#/components/schemas/ResultPage"},"type":"object","title":"Pages"}},"type":"object","title":"ResultDevice"},"ResultPage":{"properties":{"page_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Page Url"},"error":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Error"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score"},"scores":{"items":{"$ref":"#/components/schemas/ScoreEntry"},"type":"array","title":"Scores"}},"type":"object","title":"ResultPage","description":"One page's result. Asset URLs (screenshot / lighthouse) are intentionally\nomitted — reach the screenshot only via the access-controlled proxy."},"ResultTtfbPhase":{"properties":{"range_dns":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Dns"},"range_connection":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Connection"},"range_ssl":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Ssl"},"range_server":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Server"},"range_transfer":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Transfer"},"total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total"}},"type":"object","title":"ResultTtfbPhase"},"ReviewStatus":{"type":"string","enum":["pending","approved","blocked"],"title":"ReviewStatus","description":"Where an organization stands in the anti-abuse review.\n\nTHE single source of truth for the ingestion gate: an org may create\napplications and sites (and therefore obtain an embed) AND ingest beacons if\nand only if this is `APPROVED`. There is deliberately no mirrored boolean —\nregistration and org creation are open to everyone, what is gated is data\ningestion.\n\nThree states, mirroring the account model: an admin approves an org or turns\nit OFF (`BLOCKED` — declines it, stopping ingestion), with an optional owner\nnotification as a flag on the action rather than a separate status. `PENDING`\nis the queue an org lands in on creation."},"Role":{"type":"string","enum":["owner","member","viewer"],"title":"Role","description":"Role for organization members.\n\nA named bundle of permissions, not a capability in itself - what each role\nmay do lives in `app/core/permissions.py`. Ordered weakest to strongest:\n\n- `VIEWER` reads everything the dashboards show and changes nothing. It is\n  the seat for the public demo login, for read-only guests, and the floor a\n  scoped API token can be cut down to.\n- `MEMBER` is everyday work: sites, applications, releases, synthetic pages,\n  issue triage, inviting other members.\n- `OWNER` additionally owns the org itself: settings, billing-relevant\n  consent, members, partners, notification rules, deletion."},"RuleCreate":{"properties":{"name":{"type":"string","maxLength":100,"minLength":1,"title":"Name"},"is_active":{"type":"boolean","title":"Is Active","default":true},"scope_type":{"$ref":"#/components/schemas/ScopeType"},"site_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id"},"tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag"},"metric":{"type":"string","title":"Metric"},"aggregation":{"type":"string","title":"Aggregation"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity"},"operator":{"$ref":"#/components/schemas/Operator"},"condition_type":{"$ref":"#/components/schemas/ConditionType"},"threshold":{"type":"number","title":"Threshold"},"window_seconds":{"type":"integer","title":"Window Seconds"},"baseline_window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Baseline Window Seconds"},"filters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filters"},"re_notify_after_seconds":{"anyOf":[{"type":"integer","minimum":3600.0},{"type":"null"}],"title":"Re Notify After Seconds"},"actions":{"items":{"$ref":"#/components/schemas/ActionCreate"},"type":"array","maxItems":10,"minItems":1,"title":"Actions"}},"type":"object","required":["name","scope_type","metric","aggregation","operator","condition_type","threshold","window_seconds","actions"],"title":"RuleCreate"},"RuleResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"name":{"type":"string","title":"Name"},"is_active":{"type":"boolean","title":"Is Active"},"scope_type":{"$ref":"#/components/schemas/ScopeType"},"site_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Site Id"},"tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag"},"metric":{"type":"string","title":"Metric"},"aggregation":{"type":"string","title":"Aggregation"},"identity":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Identity"},"operator":{"$ref":"#/components/schemas/Operator"},"condition_type":{"$ref":"#/components/schemas/ConditionType"},"threshold":{"type":"number","title":"Threshold"},"window_seconds":{"type":"integer","title":"Window Seconds"},"baseline_window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Baseline Window Seconds"},"filters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filters"},"re_notify_after_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Re Notify After Seconds"},"last_evaluated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Evaluated At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"actions":{"items":{"$ref":"#/components/schemas/ActionResponse"},"type":"array","title":"Actions"}},"type":"object","required":["id","organization_id","name","is_active","scope_type","site_id","tag","metric","aggregation","identity","operator","condition_type","threshold","window_seconds","baseline_window_seconds","filters","re_notify_after_seconds","last_evaluated_at","created_at","updated_at","actions"],"title":"RuleResponse"},"RuleUpdate":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":100,"minLength":1},{"type":"null"}],"title":"Name"},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"},"threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Threshold"},"window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Window Seconds"},"baseline_window_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Baseline Window Seconds"},"operator":{"anyOf":[{"$ref":"#/components/schemas/Operator"},{"type":"null"}]},"re_notify_after_seconds":{"anyOf":[{"type":"integer","minimum":3600.0},{"type":"null"}],"title":"Re Notify After Seconds"},"filters":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Filters"},"actions":{"anyOf":[{"items":{"$ref":"#/components/schemas/ActionUpdate"},"type":"array","maxItems":10},{"type":"null"}],"title":"Actions"}},"type":"object","title":"RuleUpdate"},"ScopeType":{"type":"string","enum":["site","tag"],"title":"ScopeType"},"ScoreEntry":{"properties":{"name":{"type":"string","title":"Name"},"value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Value"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score"}},"type":"object","required":["name"],"title":"ScoreEntry"},"SearchApplicationRef":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"}},"type":"object","required":["id","name"],"title":"SearchApplicationRef"},"SearchOrganizationRef":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"role":{"anyOf":[{"$ref":"#/components/schemas/Role"},{"type":"null"}]},"access":{"anyOf":[{"type":"string","enum":["member","partner","admin"]},{"type":"null"}],"title":"Access"}},"type":"object","required":["id","name"],"title":"SearchOrganizationRef","description":"The organization a hit lives in, with the caller's standing there.\n\n`role` and `access` are both None for a credential the organization owns:\nthere is no person and no membership, the same way `GET /organizations`\nreports it. Being None, they are omitted from the serialized response\nrather than sent as `null` (`StandardAPIRoute`, API_STANDARDS §7)."},"SearchResponse":{"properties":{"query":{"type":"string","title":"Query"},"limit":{"type":"integer","title":"Limit"},"organizations":{"items":{"$ref":"#/components/schemas/OrganizationHit"},"type":"array","title":"Organizations"},"applications":{"items":{"$ref":"#/components/schemas/ApplicationHit"},"type":"array","title":"Applications"},"sites":{"items":{"$ref":"#/components/schemas/SiteHit"},"type":"array","title":"Sites"}},"type":"object","required":["query","limit","organizations","applications","sites"],"title":"SearchResponse","description":"One object holding three bounded lists, deliberately without `{data,\nmeta}`.\n\nRegistered as an exemption in API_STANDARDS §9 rather than left looking\nlike an oversight: there is no resume point for a cursor or an offset to\nname, and a per-kind `total` would be three numbers a palette cannot act\non. `docs/search.md` carries the reasoning."},"SendResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"rule_id":{"type":"string","format":"uuid","title":"Rule Id"},"site_id":{"type":"string","format":"uuid","title":"Site Id"},"sent_at":{"type":"string","format":"date-time","title":"Sent At"},"metric_value":{"type":"number","title":"Metric Value"},"context":{"additionalProperties":true,"type":"object","title":"Context"},"delivery_log":{"items":{},"type":"array","title":"Delivery Log"}},"type":"object","required":["id","rule_id","site_id","sent_at","metric_value","context","delivery_log"],"title":"SendResponse"},"ServerTimingCacheAgeItem":{"properties":{"layer":{"type":"string","title":"Layer","description":"cdn | origin | content. `content` is cdn + origin over the pageviews where the CDN served a HIT: the age of what the visitor actually saw, because the origin header froze inside the CDN object. It cannot be derived from the other two rows (the p75 of a sum is not the sum of the p75s), which is why it is computed here."},"count":{"type":"integer","title":"Count","description":"Pageviews reporting this age (the n behind the percentiles)"},"p50_s":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"P50 S"},"p75_s":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"P75 S"},"p95_s":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"P95 S"}},"type":"object","required":["layer","count"],"title":"ServerTimingCacheAgeItem","description":"Cache-age percentiles for one layer, in SECONDS.\n\nDeliberately not part of `phases`: those are milliseconds, these are\nseconds, and one block mixing both units is a bug waiting to be written.\nThe `_s` suffix follows `ServerTimingKeyItem.p75_ms` for the same reason."},"ServerTimingCacheItem":{"properties":{"layer":{"type":"string","title":"Layer","description":"cdn | origin"},"status":{"type":"string","title":"Status","description":"Normalized cache status (HIT/MISS/...)"},"count":{"type":"integer","title":"Count","description":"Pageviews with this status"}},"type":"object","required":["layer","status","count"],"title":"ServerTimingCacheItem","description":"Cache-status distribution for one layer."},"ServerTimingKeyItem":{"properties":{"key":{"type":"string","title":"Key","description":"Server-Timing key (catalog or custom)"},"count":{"type":"integer","title":"Count","description":"Pageviews carrying this key"},"p75_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P75 Ms","description":"p75 of the key's duration (None = no duration ever reported)"},"values":{"items":{"$ref":"#/components/schemas/ServerTimingKeyValue"},"type":"array","title":"Values","description":"Most frequent desc values of this key (empty = no desc ever reported)"}},"type":"object","required":["key","count"],"title":"ServerTimingKeyItem","description":"One Tier-2/3 custom key from server_timing_dur and/or server_timing_desc.\n\nA key can be timed (`dur`), categorical (`desc`) or both, so both halves are\noptional: `p75_ms` is None for a key that never carried a duration (e.g.\n`Server-Timing: pop;desc=\"DE-1331\"`), `values` is empty for a pure duration\nkey. `count` is the pageviews carrying the key in either map."},"ServerTimingKeyValue":{"properties":{"value":{"type":"string","title":"Value","description":"The header's desc text (e.g. 'DE-1331')"},"count":{"type":"integer","title":"Count","description":"Pageviews carrying this key/value pair"}},"type":"object","required":["value","count"],"title":"ServerTimingKeyValue","description":"One observed `desc` value of a categorical Server-Timing key."},"ServerTimingPhaseItem":{"properties":{"phase":{"type":"string","title":"Phase","description":"edge_dur/origin_dur/backend_dur/db_dur/http_dur/render_dur/search_dur/kv_dur"},"count":{"type":"integer","title":"Count","description":"Pageviews reporting this phase (the n behind the percentiles)"},"p50":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P50"},"p75":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P75"},"p95":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P95"}},"type":"object","required":["phase","count"],"title":"ServerTimingPhaseItem","description":"Percentiles of one backend-phase duration (ms), with their sample size."},"ServerTimingRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","description":"Max custom keys (top_keys block)","default":20}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"ServerTimingRequest","description":"Request for the Server-Timing dashboard panel."},"ServerTimingResponse":{"properties":{"cache":{"items":{"$ref":"#/components/schemas/ServerTimingCacheItem"},"type":"array","title":"Cache","description":"Cache-status distribution"},"cache_age":{"items":{"$ref":"#/components/schemas/ServerTimingCacheAgeItem"},"type":"array","title":"Cache Age","description":"Cache-age percentiles per layer, in seconds (migration 072)"},"phases":{"items":{"$ref":"#/components/schemas/ServerTimingPhaseItem"},"type":"array","title":"Phases","description":"Backend-phase percentiles"},"top_keys":{"items":{"$ref":"#/components/schemas/ServerTimingKeyItem"},"type":"array","title":"Top Keys","description":"Top custom keys by p75"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["cache","phases","top_keys","execution_time_ms"],"title":"ServerTimingResponse","description":"Response for the Server-Timing dashboard panel: four blocks."},"SessionConsent":{"type":"string","enum":["deferred","immediate"],"title":"SessionConsent","description":"When the served bundle writes the session identifier under consent (only\nmeaningful when `collect_sessions` is on).\n\nDEFERRED  — defer the session write until `window.fastmon.grantConsent()` is\n            called (consent-first; the privacy-safe default).\nIMMEDIATE — write the session on load (consent already handled / not required)."},"SiteCreate":{"properties":{"application_id":{"type":"string","format":"uuid","title":"Application Id"},"name":{"type":"string","title":"Name"},"domain":{"type":"string","title":"Domain"},"data_retention_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Data Retention Days"},"store_stitch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Store Stitch"},"count_visitors_by":{"anyOf":[{"$ref":"#/components/schemas/VisitorIdentity"},{"type":"null"}]},"tags":{"items":{"type":"string"},"type":"array","maxItems":10,"title":"Tags","default":[]}},"type":"object","required":["application_id","name","domain"],"title":"SiteCreate","description":"Create a site (a domain / analytics unit) under an existing application.\n\nA site is pure domain/analytics; the embed + all collection config live on the\napplication (`application_id`, required). Only the domain, a display name, tags,\nand the three per-domain overrides are set here. Each override is NULL by\ndefault = inherit the application's value; a non-null value overrides it."},"SiteHit":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"domain":{"type":"string","title":"Domain"},"is_active":{"type":"boolean","title":"Is Active"},"organization":{"$ref":"#/components/schemas/SearchOrganizationRef"},"application":{"$ref":"#/components/schemas/SearchApplicationRef"}},"type":"object","required":["id","name","domain","is_active","organization","application"],"title":"SiteHit"},"SitePolicy":{"type":"string","enum":["open","auto","strict"],"title":"SitePolicy","description":"How an application handles an UNKNOWN beacon hostname (one with no matching\nregistered Site). Replaces the old `auto_provision_sites` flag and the per-Site\n`enforce_domain_match`.\n\nOPEN   — record a discovery suggestion, drop the beacon (default).\nAUTO   — auto-create a Site for the hostname.\nSTRICT — drop; no suggestion, no auto-provision, no one-site lenient bind\n         (only exactly-registered domains are served)."},"SiteResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"organization_id":{"type":"string","format":"uuid","title":"Organization Id"},"application_id":{"type":"string","format":"uuid","title":"Application Id"},"name":{"type":"string","title":"Name"},"domain":{"type":"string","title":"Domain"},"is_active":{"type":"boolean","title":"Is Active"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"data_retention_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Data Retention Days"},"store_stitch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Store Stitch"},"count_visitors_by":{"anyOf":[{"$ref":"#/components/schemas/VisitorIdentity"},{"type":"null"}]}},"type":"object","required":["id","organization_id","application_id","name","domain","is_active"],"title":"SiteResponse","description":"A site: a pure domain / analytics unit belonging to one application.\n\nThe embed + collection config live on the application (fetch it via\n`application_id`); they are NOT mirrored here. The three per-domain fields are\nreturned RAW: NULL = inherits the application's default, a non-null value\noverrides it (the FE resolves the effective value against the application)."},"SiteStatusResponse":{"properties":{"beacons_today":{"type":"integer","title":"Beacons Today"},"beacons_per_minute":{"type":"number","title":"Beacons Per Minute"},"last_beacon_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Beacon At"}},"type":"object","required":["beacons_today","beacons_per_minute"],"title":"SiteStatusResponse"},"SiteUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"data_retention_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Data Retention Days"},"store_stitch":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Store Stitch"},"count_visitors_by":{"anyOf":[{"$ref":"#/components/schemas/VisitorIdentity"},{"type":"null"}]},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"},"tags":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":10},{"type":"null"}],"title":"Tags"}},"type":"object","title":"SiteUpdate"},"SiteUsage":{"properties":{"site_id":{"type":"string","format":"uuid","title":"Site Id"},"site_name":{"type":"string","title":"Site Name"},"beacon_count":{"type":"integer","title":"Beacon Count"}},"type":"object","required":["site_id","site_name","beacon_count"],"title":"SiteUsage"},"SortDirection":{"type":"string","enum":["asc","desc"],"title":"SortDirection","description":"Sort order direction."},"SparklinePoint":{"properties":{"ts":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ts"},"desktop_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Desktop Score"},"mobile_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mobile Score"}},"type":"object","title":"SparklinePoint","description":"One run's score in a sparkline series (newest first). CS scores are sums →\nfloat-safe."},"Storage":{"type":"string","enum":["shared","dedicated","external"],"title":"Storage","description":"Storage mode for organization data."},"SymbolicatedFrame":{"properties":{"index":{"type":"integer","title":"Index","description":"Position in the stack, 0 is the top frame."},"host":{"type":"string","title":"Host"},"path":{"type":"string","title":"Path"},"line":{"type":"integer","title":"Line"},"column":{"type":"integer","title":"Column"},"status":{"type":"string","enum":["resolved","host_only","foreign_host","position_gone","no_position","unreachable","unavailable"],"title":"Status"},"module_id":{"type":"string","title":"Module Id","description":"Enclosing webpack module id, '' if none.","default":""},"method":{"type":"string","title":"Method","description":"Nearest preceding named method or function.","default":""},"object":{"type":"string","title":"Object","description":"Object of the member access at the column.","default":""},"property":{"type":"string","title":"Property","description":"Property of the member access at the column.","default":""},"snippet":{"type":"string","title":"Snippet","description":"Code around the column.","default":""},"caret_at":{"type":"integer","title":"Caret At","description":"Byte offset of the column inside `snippet`.","default":0},"near_boundary":{"type":"boolean","title":"Near Boundary","description":"The position sits close behind the method head, so the attribution may belong to the previous scope.","default":false},"throw_kind":{"type":"string","enum":["","origin","rethrow"],"title":"Throw Kind","description":"Where a `throw` sits at the caret. 'origin' creates the error here, so this frame plus the message is the whole diagnosis. 'rethrow' only passes on something caught further down.","default":""},"library":{"type":"string","title":"Library","description":"The well-known library this file is, e.g. 'jQuery', or '' when the file is not recognised. Decided by file name, not by host: a shop serves jQuery from its own domain. Set whatever the status is, because the name is read off the path rather than off the bundle.","default":""}},"type":"object","required":["index","host","path","line","column","status"],"title":"SymbolicatedFrame","description":"One stack frame resolved against the file the browser actually ran.\n\n`status` says what happened, and only \"resolved\" fills the code fields:\n\n- `resolved`: the file was fetched and the position found.\n- `host_only`: no path was stored, so there is nothing to fetch. Inline and\n  third-party frames without the frame opt-in.\n- `foreign_host`: the frame points at a host that is not a registered site\n  domain of this organization. Never fetched.\n- `position_gone`: the file no longer has that line and column, which is what\n  a redeploy under an unchanged name looks like.\n- `no_position`: the browser reported the file but no line and column.\n- `unreachable`: the file could not be fetched.\n- `unavailable`: symbolication is switched off or the service did not answer."},"SyntheticAnalysisStatus":{"properties":{"analysis_uuid":{"type":"string","title":"Analysis Uuid"},"status":{"type":"integer","title":"Status"},"percent":{"type":"integer","title":"Percent"},"done":{"type":"boolean","title":"Done"}},"type":"object","required":["analysis_uuid","status","percent","done"],"title":"SyntheticAnalysisStatus","description":"Progress of an in-flight analysis (for run UX)."},"SyntheticPageCreate":{"properties":{"url":{"type":"string","maxLength":2048,"title":"Url"},"mode":{"type":"string","enum":["monitor","oneshot"],"title":"Mode","default":"monitor"},"schedule":{"type":"boolean","title":"Schedule","default":true},"ttfb_schedule":{"type":"boolean","title":"Ttfb Schedule","default":true},"nocache":{"type":"boolean","title":"Nocache","default":true}},"type":"object","required":["url"],"title":"SyntheticPageCreate","description":"Create a synthetic page. The URL is normalized to the beacon form and must be\nunder the site's own domain. Registering always runs one immediate analysis.\n\n`mode` picks the intent:\n- `monitor` (default): a sticky, quota-counted page. `schedule` (recurring 24h\n  Lighthouse, default on) and `ttfb_schedule` (recurring 5-min CS, default on) are\n  honored — set either false to register paused / opt out; the flags govern only\n  the *recurring* runs.\n- `oneshot`: an unbudgeted \"measure now\". The schedule flags are ignored (both\n  forced off), `nocache` is forced true (fresh origin fetch), and the single\n  creation run is mandatory — a missing run id is a hard 502, not tolerated."},"SyntheticPageCreateResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"site_id":{"type":"string","format":"uuid","title":"Site Id"},"url":{"type":"string","title":"Url"},"source":{"$ref":"#/components/schemas/SyntheticPageSource"},"auto_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Auto Rank"},"cs_site_uuid":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cs Site Uuid"},"schedule":{"type":"boolean","title":"Schedule"},"ttfb_schedule":{"type":"boolean","title":"Ttfb Schedule"},"nocache":{"type":"boolean","title":"Nocache"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"analysis_uuid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Uuid"},"analysis_status":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Analysis Status"}},"type":"object","required":["id","site_id","url","source","auto_rank","cs_site_uuid","schedule","ttfb_schedule","nocache","created_at"],"title":"SyntheticPageCreateResponse","description":"A created/registered page plus the run that creation always triggers.\n\nCreating a CS site kicks off one immediate analysis regardless of the schedule\nflags — the flags gate only the *recurring* runs, so even a page created paused\n(`schedule=false`) produces this one creation run. Both manual create and one-shot\nsurface its `analysis_uuid` for the client to poll, instead of firing a redundant\nsecond run. `analysis_uuid` is null only if CS registered the site but returned\nno run id (manual create tolerates that; one-shot 502s)."},"SyntheticPageListItem":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"site_id":{"type":"string","format":"uuid","title":"Site Id"},"url":{"type":"string","title":"Url"},"source":{"$ref":"#/components/schemas/SyntheticPageSource"},"auto_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Auto Rank"},"cs_site_uuid":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cs Site Uuid"},"schedule":{"type":"boolean","title":"Schedule"},"ttfb_schedule":{"type":"boolean","title":"Ttfb Schedule"},"nocache":{"type":"boolean","title":"Nocache"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"summary":{"anyOf":[{"$ref":"#/components/schemas/SyntheticPageSummary"},{"type":"null"}]}},"type":"object","required":["id","site_id","url","source","auto_rank","cs_site_uuid","schedule","ttfb_schedule","nocache","created_at"],"title":"SyntheticPageListItem","description":"A page plus an optional last-result summary (populated when `summary=true`)."},"SyntheticPageResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"site_id":{"type":"string","format":"uuid","title":"Site Id"},"url":{"type":"string","title":"Url"},"source":{"$ref":"#/components/schemas/SyntheticPageSource"},"auto_rank":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Auto Rank"},"cs_site_uuid":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Cs Site Uuid"},"schedule":{"type":"boolean","title":"Schedule"},"ttfb_schedule":{"type":"boolean","title":"Ttfb Schedule"},"nocache":{"type":"boolean","title":"Nocache"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","site_id","url","source","auto_rank","cs_site_uuid","schedule","ttfb_schedule","nocache","created_at"],"title":"SyntheticPageResponse"},"SyntheticPageSource":{"type":"string","enum":["manual","auto","oneshot"],"title":"SyntheticPageSource","description":"How a synthetic page was added."},"SyntheticPageSummary":{"properties":{"last_run_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Run At"},"desktop_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Desktop Score"},"mobile_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mobile Score"}},"type":"object","required":["last_run_at","desktop_score","mobile_score"],"title":"SyntheticPageSummary","description":"Compact last-result health snapshot for list rows (avoids the N+1 of\nfetching results per page from the client)."},"SyntheticPageUpdate":{"properties":{"schedule":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Schedule"},"ttfb_schedule":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Ttfb Schedule"},"nocache":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Nocache"}},"type":"object","title":"SyntheticPageUpdate","description":"Patch monitoring config. All optional; only provided fields change.\n`schedule=false` pauses the recurring Lighthouse run — the page stays and is\nstill runnable on demand. `nocache` toggles CS cache-bypass for future runs."},"SyntheticQuota":{"properties":{"manual_used":{"type":"integer","title":"Manual Used"},"manual_limit":{"type":"integer","title":"Manual Limit"},"auto_used":{"type":"integer","title":"Auto Used"},"auto_limit":{"type":"integer","title":"Auto Limit"}},"type":"object","required":["manual_used","manual_limit","auto_used","auto_limit"],"title":"SyntheticQuota","description":"Org-wide synthetic page budget. Manual and auto pages have independent caps\n(derived from the org plan); one-shots are unbounded and not counted. Usage spans\nALL sites in the org, so it can exceed this site's `page_count`."},"SyntheticResultItem":{"properties":{"analysis_uuid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Uuid"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"data":{"additionalProperties":{"$ref":"#/components/schemas/ResultDevice"},"type":"object","title":"Data"},"data_ttfb":{"additionalProperties":{"$ref":"#/components/schemas/ResultTtfbPhase"},"type":"object","title":"Data Ttfb"}},"type":"object","title":"SyntheticResultItem"},"SyntheticResultsResponse":{"properties":{"total":{"type":"integer","title":"Total"},"results":{"items":{"$ref":"#/components/schemas/SyntheticResultItem"},"type":"array","title":"Results"}},"type":"object","required":["total","results"],"title":"SyntheticResultsResponse","description":"Shaped synthetic-monitoring result history. Asset URLs are stripped;\nscreenshots come from the proxy endpoint only."},"SyntheticRunListItem":{"properties":{"analysis_uuid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analysis Uuid"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"desktop_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Desktop Score"},"mobile_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Mobile Score"}},"type":"object","title":"SyntheticRunListItem","description":"One run, trimmed to what a run-selector needs: id + when + per-device score.\nDeliberately omits scores[]/ttfb/curation so the selector payload stays small."},"SyntheticRunResponse":{"properties":{"analysis_uuid":{"type":"string","title":"Analysis Uuid"},"site_uuid":{"type":"string","title":"Site Uuid"},"status":{"type":"integer","title":"Status"}},"type":"object","required":["analysis_uuid","site_uuid","status"],"title":"SyntheticRunResponse","description":"Result of triggering an on-demand analysis."},"SyntheticRunsResponse":{"properties":{"total":{"type":"integer","title":"Total"},"runs":{"items":{"$ref":"#/components/schemas/SyntheticRunListItem"},"type":"array","title":"Runs"}},"type":"object","required":["total","runs"],"title":"SyntheticRunsResponse","description":"Lightweight run list for the run-selector (live from CS)."},"SyntheticSummaryResponse":{"properties":{"site_id":{"type":"string","format":"uuid","title":"Site Id"},"page_count":{"type":"integer","title":"Page Count"},"total_runs":{"type":"integer","title":"Total Runs"},"aggregate_desktop_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Aggregate Desktop Score"},"aggregate_mobile_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Aggregate Mobile Score"},"pages":{"items":{"$ref":"#/components/schemas/PageSparkline"},"type":"array","title":"Pages"},"partial":{"type":"boolean","title":"Partial","default":false},"quota":{"$ref":"#/components/schemas/SyntheticQuota"}},"type":"object","required":["site_id","page_count","total_runs","aggregate_desktop_score","aggregate_mobile_score","pages","quota"],"title":"SyntheticSummaryResponse","description":"Site-wide synthetic overview: aggregate latest score across pages, total runs,\nand a per-page sparkline each. Computed live from cached per-page series — no\nstored aggregate (CS stays the system of record)."},"TestSendResponse":{"properties":{"rule_id":{"type":"string","format":"uuid","title":"Rule Id"},"delivery_log":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Delivery Log"}},"type":"object","required":["rule_id","delivery_log"],"title":"TestSendResponse"},"ThirdPartyItem":{"properties":{"domain":{"type":"string","title":"Domain","description":"Third-party domain"},"count":{"type":"integer","title":"Count","description":"Number of occurrences"}},"type":"object","required":["domain","count"],"title":"ThirdPartyItem","description":"Single third-party domain with data."},"ThirdPartyRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"limit":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Limit","description":"Max domains to return","default":10}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"ThirdPartyRequest","description":"Request for third-party blocking domains."},"ThirdPartyResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/ThirdPartyItem"},"type":"array","title":"Data","description":"Third-party domains"},"total_count":{"type":"integer","title":"Total Count","description":"Total third-party resources"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["data","total_count","execution_time_ms"],"title":"ThirdPartyResponse","description":"Response for third-party blocking domains."},"TimeRange":{"properties":{"from":{"type":"string","format":"date-time","title":"From","description":"Start of time range (inclusive)"},"to":{"type":"string","format":"date-time","title":"To","description":"End of time range (exclusive)"}},"type":"object","required":["from","to"],"title":"TimeRange","description":"Required time range for queries."},"TimeseriesResponse":{"properties":{"page_id":{"type":"string","format":"uuid","title":"Page Id"},"url":{"type":"string","title":"Url"},"device":{"type":"string","title":"Device"},"window_days":{"type":"integer","title":"Window Days"},"interval":{"type":"string","title":"Interval"},"lab":{"items":{"$ref":"#/components/schemas/LabPoint"},"type":"array","title":"Lab"},"ttfb":{"items":{"$ref":"#/components/schemas/TtfbSeriesPoint"},"type":"array","title":"Ttfb"},"field":{"items":{"$ref":"#/components/schemas/FieldPoint"},"type":"array","title":"Field"}},"type":"object","required":["page_id","url","device","window_days","interval","lab","ttfb","field"],"title":"TimeseriesResponse","description":"Series for charting, different time granularities by design: sparse `lab`\npoints (Lighthouse) and raw `ttfb` points (dedicated 5-min schedule) overlaid on\nthe regular `field` p75 line. `lab.ttfb` is Lighthouse's server-only TTFB; the\n`ttfb` series is the full phase breakdown — they are not the same measurement."},"TtfbDiagnosisResponse":{"properties":{"page_id":{"type":"string","format":"uuid","title":"Page Id"},"url":{"type":"string","title":"Url"},"window_days":{"type":"integer","title":"Window Days"},"lab_phases":{"anyOf":[{"$ref":"#/components/schemas/TtfbPhases"},{"type":"null"}]},"devices":{"items":{"$ref":"#/components/schemas/TtfbFieldDevice"},"type":"array","title":"Devices"}},"type":"object","required":["page_id","url","window_days","lab_phases","devices"],"title":"TtfbDiagnosisResponse"},"TtfbFieldDevice":{"properties":{"device":{"type":"string","title":"Device"},"field_ttfb_p75":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Field Ttfb P75"},"field_dns_p75":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Field Dns P75"},"field_tcp_p75":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Field Tcp P75"},"samples":{"type":"integer","title":"Samples"},"sufficient":{"type":"boolean","title":"Sufficient"},"verdict":{"type":"string","title":"Verdict"}},"type":"object","required":["device","field_ttfb_p75","field_dns_p75","field_tcp_p75","samples","sufficient","verdict"],"title":"TtfbFieldDevice"},"TtfbPhases":{"properties":{"range_dns":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Dns"},"range_connection":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Connection"},"range_ssl":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Ssl"},"range_server":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Server"},"range_transfer":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Transfer"},"total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total"},"server_dominant":{"type":"boolean","title":"Server Dominant"}},"type":"object","required":["range_dns","range_connection","range_ssl","range_server","range_transfer","total","server_dominant"],"title":"TtfbPhases","description":"CS server-side TTFB phase breakdown (ms), once per page (not per device)."},"TtfbSeriesPoint":{"properties":{"ts":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ts"},"range_dns":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Dns"},"range_connection":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Connection"},"range_ssl":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Ssl"},"range_server":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Server"},"range_transfer":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Range Transfer"},"total":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total"}},"type":"object","required":["ts","range_dns","range_connection","range_ssl","range_server","range_transfer","total"],"title":"TtfbSeriesPoint","description":"One dedicated TTFB run (5-min schedule): raw DNS→transfer phases + total (ms).\nDevice-independent — CS measures TTFB once per run, not per device."},"UnknownHostnameSuggestion":{"properties":{"hostname":{"type":"string","title":"Hostname"},"hits":{"type":"integer","title":"Hits"},"application_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Application Id"},"application_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Application Name"}},"type":"object","required":["hostname","hits"],"title":"UnknownHostnameSuggestion","description":"A hostname observed hitting an application that matched no registered site —\na candidate to adopt as a new site (one site per domain). The observed value\nis a hostname (`urlparse().hostname`, port-free); the customer registers it as\na `Site.domain`. `application_id`/`application_name` say WHICH application\nobserved it (null only for legacy ephemeral entries recorded before the\napplication dimension existed)."},"UnknownHostnamesResponse":{"properties":{"suggestions":{"items":{"$ref":"#/components/schemas/UnknownHostnameSuggestion"},"type":"array","title":"Suggestions"}},"type":"object","required":["suggestions"],"title":"UnknownHostnamesResponse"},"UsageResponse":{"properties":{"total_beacons":{"type":"integer","title":"Total Beacons"},"period_start":{"type":"string","format":"date-time","title":"Period Start"},"period_end":{"type":"string","format":"date-time","title":"Period End"},"sites":{"items":{"$ref":"#/components/schemas/SiteUsage"},"type":"array","title":"Sites"}},"type":"object","required":["total_beacons","period_start","period_end","sites"],"title":"UsageResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VisitorAggregateFilters":{"properties":{"min_page_count":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Min Page Count"},"max_page_count":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Page Count"},"min_duration_ms":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Min Duration Ms"},"max_duration_ms":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Duration Ms"},"min_avg_lcp_ms":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Min Avg Lcp Ms"},"max_avg_lcp_ms":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Max Avg Lcp Ms"},"min_errors":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Min Errors"},"contains_page_type":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Contains Page Type","description":"Only visitors whose session includes >=1 pageview of this page_type"},"contains_checkout_stage":{"anyOf":[{"type":"string","maxLength":32},{"type":"null"}],"title":"Contains Checkout Stage","description":"Only visitors whose session includes >=1 pageview at this checkout-funnel stage (cart/checkout/success). This is what turns the visitors list into 'everyone who bought' / 'everyone who reached checkout'; the per-visitor journey then comes from /visitors/detail."},"contains_cart_interaction":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Contains Cart Interaction","description":"True: only visitors whose session issued >=1 cart interaction (fetch/XHR cart mutation - add, change or remove; the kinds are not separable, see migration 065). False: only visitors with NONE observed. Omitted/null: no filter."}},"additionalProperties":false,"type":"object","title":"VisitorAggregateFilters","description":"Post-aggregation filters for `/visitors`.\n\nThese apply AFTER the `GROUP BY` on the resolved identity, so they emit HAVING\nclauses rather than WHERE. Fields are independent; omit any to skip that bound.\nNull `avg_lcp` rows (visitors with no LCP measurements) are excluded from any\n`min_avg_lcp_ms`/`max_avg_lcp_ms` bound."},"VisitorDetailRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity","description":"Identifier kind for `id`: 'session' or 'stitch'. Null resolves the same way the visitor list does (site's preferred/available identity)."},"id":{"type":"string","minLength":1,"title":"Id","description":"Visitor ID to retrieve (session_id or stitch)"}},"additionalProperties":false,"type":"object","required":["time_range","id"],"title":"VisitorDetailRequest","description":"Request for visitor detail (all page visits)."},"VisitorDetailResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Visitor identifier (stitch hex or session_id)"},"identity":{"type":"string","title":"Identity","description":"Identifier kind for `id`: stitch | session"},"pages":{"items":{"$ref":"#/components/schemas/VisitorPageVisit"},"type":"array","title":"Pages","description":"Chronological page visits"},"execution_time_ms":{"type":"number","title":"Execution Time Ms","description":"Query execution time"}},"type":"object","required":["id","identity","pages","execution_time_ms"],"title":"VisitorDetailResponse","description":"Response for visitor detail query."},"VisitorIdentity":{"type":"string","enum":["stitch","session"],"title":"VisitorIdentity","description":"Which identifier the `visitors` metric defaults to in reports (the\n`count_visitors_by` field). A REPORTING preference, deliberately separate from\nthe store_stitch/collect_sessions COLLECTION flags (those decide whether the\ndata exists at all). The query-time resolver clamps this to what the site\nactually stores, and a per-query `identity` param overrides it. See\nresolve_identity()."},"VisitorPageVisit":{"properties":{"url":{"type":"string","title":"Url","description":"Page URL"},"started_at":{"type":"string","format":"date-time","title":"Started At","description":"Pageview start (wall-clock). Anchor for replay timelines."},"ended_at":{"type":"string","format":"date-time","title":"Ended At","description":"Pageview end (wall-clock): close-out / hidden / terminated moment. Together with `started_at` gives true pageview duration."},"nav_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Nav Type","description":"Navigation type"},"lcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp","description":"Largest Contentful Paint (ms)"},"fcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Fcp","description":"First Contentful Paint (ms)"},"cls":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cls","description":"Cumulative Layout Shift"},"inp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp","description":"Interaction to Next Paint (ms)"},"ttfb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ttfb","description":"Time to First Byte (ms)"},"ttfb_final":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ttfb Final","description":"TTFB of the final (non-interim) response (ms); null off-Chromium. Larger than ttfb when 103 Early Hints were in play."},"page_load_time":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Page Load Time","description":"Full page load time (ms)"},"cdn_cache_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cdn Cache Status","description":"CDN cache status for this pageview (HIT/MISS/…), if collected"},"origin_cache_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin Cache Status","description":"Origin cache status for this pageview (HIT/MISS/…), if collected"},"page_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Page Type","description":"Page type for this pageview (product/category/cart/…), if detected"},"origin_host":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Origin Host","description":"Origin node that served this pageview (`fm-host`), if reported"},"logged_in":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logged In","description":"Whether this pageview was rendered for a logged-in visitor (`fm-loggedin`): 'yes' / 'no'; null if not reported"},"cdn_age":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cdn Age","description":"Age of the delivered CDN cache object in SECONDS (`fm-cdn-age`), if reported"},"origin_age":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Origin Age","description":"Age of the delivered origin cache object in SECONDS (`fm-origin-age`), if reported. Under a CDN hit this is the age at fetch time, frozen in the CDN object - the age the visitor saw is cdn_age + origin_age."},"checkout_stage":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Checkout Stage","description":"Checkout-funnel stage of THIS pageview (cart/checkout/success); null for every pageview outside the funnel. The hook sits on the matching pageview only - the surrounding journey is in this same list because it belongs to the same visitor, not because it is marked."},"cart_interactions":{"type":"integer","title":"Cart Interactions","description":"Cart interactions (fetch/XHR cart mutations) THIS pageview issued; 0 = none observed.","default":0},"cart_interaction_errors":{"type":"integer","title":"Cart Interaction Errors","description":"Of those, failed ones (HTTP >= 400 or network failure) - the 'cart actions are failing' signal.","default":0},"cart_interaction_kinds":{"additionalProperties":{"type":"integer"},"type":"object","title":"Cart Interaction Kinds","description":"Kind -> calls (add/change/remove/other), where the shop system's endpoint reveals the kind."},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country","description":"Country (ISO code) of this pageview"},"browser":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Browser","description":"Browser name"},"browser_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Browser Version","description":"Browser version"},"device_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Type","description":"Device type (desktop/mobile/tablet)"},"os":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Os","description":"Operating system"},"datacenter":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Datacenter","description":"Datacenter/crawler network label (aws/googlebot/…); null = normal network"},"bot_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Name","description":"Detected bot slug ('unknown' = generic heuristic); null = no bot signal"},"bot_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Type","description":"Bot category tag (ai-crawler/search-engine/…); null = no bot signal"},"is_datacenter":{"type":"boolean","title":"Is Datacenter","description":"Derived: datacenter is set (datacenter/crawler network)","default":false},"is_bot":{"type":"boolean","title":"Is Bot","description":"Derived: bot_name is set (incl. 'unknown')","default":false},"ua_anomaly":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ua Anomaly","description":"UA consistency signal (headless/spoofed/non-browser)"},"bot_class":{"$ref":"#/components/schemas/BotClass","description":"Derived traffic verdict: bot / suspect / none","default":"none"},"lcp_ttfb":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp Ttfb","description":"LCP phase 1: time to first byte (ms)"},"lcp_load_delay":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp Load Delay","description":"LCP phase 2: resource load delay — discovery gap (ms)"},"lcp_load_duration":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp Load Duration","description":"LCP phase 3: resource load duration — download (ms)"},"lcp_render_delay":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Lcp Render Delay","description":"LCP phase 4: element render delay (ms)"},"lcp_target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lcp Target","description":"CSS selector path of the LCP element, if captured"},"cls_target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cls Target","description":"CSS selector path of the largest layout shift's element, if captured"},"inp_input_delay":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp Input Delay","description":"INP subpart: input delay of the reported interaction (ms)"},"inp_processing":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp Processing","description":"INP subpart: processing duration of the reported interaction (ms)"},"inp_presentation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inp Presentation","description":"INP subpart: presentation delay of the reported interaction (ms)"},"inp_interaction_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inp Interaction Type","description":"Reported INP interaction type (pointer/keyboard), if captured"},"inp_target":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Inp Target","description":"CSS selector path of the reported INP interaction's target, if captured"},"error_count":{"type":"integer","title":"Error Count","description":"Errors on this page","default":0},"errors":{"items":{"$ref":"#/components/schemas/BeaconError"},"type":"array","title":"Errors","description":"Structured per-beacon errors (top 5 by occurrence)"}},"type":"object","required":["url","started_at","ended_at"],"title":"VisitorPageVisit","description":"Single page visit within a visitor's activity."},"VisitorSummaryItem":{"properties":{"id":{"type":"string","title":"Id","description":"Visitor identifier (stitch hex or session_id, per `identity`)"},"identity":{"type":"string","title":"Identity","description":"Identifier this row is grouped by: stitch | session"},"started_at":{"type":"string","format":"date-time","title":"Started At","description":"First pageview start for this visitor (wall-clock)"},"ended_at":{"type":"string","format":"date-time","title":"Ended At","description":"Last pageview end for this visitor (wall-clock)"},"duration_ms":{"type":"number","title":"Duration Ms","description":"Span from first to last pageview in milliseconds"},"page_count":{"type":"integer","title":"Page Count","description":"Number of page views"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country","description":"Country (ISO code)"},"browser":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Browser","description":"Browser name"},"browser_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Browser Version","description":"Browser version"},"device_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Device Type","description":"Device type"},"os":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Os","description":"Operating system"},"avg_lcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Lcp","description":"Average LCP across pages"},"avg_fcp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Avg Fcp","description":"Average FCP across pages"},"total_errors":{"type":"integer","title":"Total Errors","description":"Total errors","default":0}},"type":"object","required":["id","identity","started_at","ended_at","duration_ms","page_count"],"title":"VisitorSummaryItem","description":"Summary of a single visitor (grouped by the resolved `identity`)."},"VisitorsListRequest":{"properties":{"time_range":{"$ref":"#/components/schemas/TimeRange","description":"Time range for the query"},"filters":{"$ref":"#/components/schemas/Filters","description":"Optional filters"},"identity":{"anyOf":[{"type":"string","enum":["stitch","session"]},{"type":"null"}],"title":"Identity","description":"Identifier to group visitors by: 'stitch' or 'session'. Null → the per-site default (stitch preferred)."},"visitor_filters":{"$ref":"#/components/schemas/VisitorAggregateFilters","description":"Post-aggregation filters (page count, duration, errors, avg LCP)"},"search":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Search","description":"Search by visitor ID"},"limit":{"type":"integer","maximum":100.0,"minimum":1.0,"title":"Limit","description":"Max visitors to return","default":50},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor","description":"Opaque pagination cursor"}},"additionalProperties":false,"type":"object","required":["time_range"],"title":"VisitorsListRequest","description":"Request for the visitors list.\n\nCursor-paginated; always ordered by (start_time DESC, id DESC). Clients that\nwant to re-sort do so over the loaded rows client-side."}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"fm_… / fmo_…","description":"API token generated from the fastmon dashboard (Account → API Token) or at organization level (`fmo_…`, one that outlives its creator). Send as `Authorization: Bearer fm_...` or paste the full token (including its prefix) into the Authorize dialog."}}},"tags":[{"name":"organizations","description":"Manage organizations: the top-level tenant that owns sites, members, and analytics data. Covers organization CRUD, usage summaries, and ownership transfer."},{"name":"members","description":"List and manage members of an organization, including their roles."},{"name":"sites","description":"Manage the sites (domains) monitored under an organization — each a domain/analytics unit belonging to one application. Includes site CRUD, tag- and application-based filtering, per-domain settings, and live beacon-receipt status. (The embed + hash rotation live on the application.)"},{"name":"applications","description":"Manage applications: the tracking embed (script + collector hashes + collection config) that a site's beacons post to. An application runs on one or more domains (its sites); each beacon's site is resolved at ingest by its page-URL host. Covers application CRUD, script/collector hash rotation, domain (site) membership, and discovery of unregistered hostnames seen hitting the application."},{"name":"releases","description":"Track releases per application so analytics can be correlated with deploys (regressions, rollouts, before/after comparisons)."},{"name":"analytics","description":"**Beta.** Query monitoring data: Core Web Vitals, performance timings, JS errors, third-party impact, sessions, and aggregate experience scores. Supports time-series and breakdown queries with filters. The response shape may still change before general availability."},{"name":"synthetic","description":"**Beta.** Synthetic monitoring (Commerce-Score): scheduled Lighthouse-style lab runs for key pages, with lab-vs-field comparison and historical trends. Requires the organization to opt in to Synthetic Monitoring; available to all organization members. Surface and response shape may still change before general availability."},{"name":"notifications","description":"Rule-based alerting on Core Web Vitals, traffic, and error metrics. Manage rules, inspect send history, run test evaluations, apply presets, and preview rules against historical data."},{"name":"partners","description":"Endpoints for partner organizations that manage multiple client organizations with aggregated billing and usage reporting."},{"name":"search","description":"Find organizations, applications and sites across everything the calling credential reaches, in one request. Reach and permissions are the ones every other endpoint applies: a key sees the organizations it was issued for, and needs `site:read` or `app:read` for those kinds. Returns one bounded list per kind rather than a paginated collection."},{"name":"collector","description":"Public beacon ingestion endpoint embedded in the browser tracker. Accepts RUM payloads from end-user devices; exempt from the standard response envelope."},{"name":"source","description":"Public delivery of the browser tracking script. ETag-cached and exempt from the standard response envelope."}],"security":[{"bearerAuth":[]}]}