{
  "openapi": "3.0.0",
  "info": {
    "title": "Kitbase API",
    "description": "Kitbase is a product-analytics, AI-visibility and crawler-analytics platform. This document describes the public REST surface of the Kitbase API — the same endpoints the Kitbase CLI (`@kitbase/cli`) and dashboard use. Machine-readable copies live at https://api.kitbase.dev/openapi.json (JSON) and https://api.kitbase.dev/openapi.yaml (YAML), mirrored at https://kitbase.dev/openapi.json. Human documentation: https://docs.kitbase.dev/api-reference.\n\n## Authentication\n\n- **Private API key** (`sk_kitbase_…`): send `Authorization: Bearer sk_kitbase_…` or `X-API-Key: sk_kitbase_…`. Keys are created in the dashboard (Project Settings → API Keys) and are bound to one project.\n- **User session** (JWT): `Authorization: Bearer <jwt>`, obtained from the login endpoints or the CLI device-login flow (`/auth/cli/sessions`).\n- **SDK key** (`pk_kitbase_…`): `x-sdk-key` header; accepted only by the `/sdk/v1/*` ingestion endpoints.\n- **Server-side ingestion** (`/ingest/v1/*`): the private API key.\n\n## Permissions and scoping\n\nEvery operation is guarded by a named permission (for example `analytics.view`, `webhook.create`, `aivisibility.manage`). A user holds the permissions of their role in the organization (owner, admin, developer, analyst, support). A private API key holds the live permissions of the user who created it, limited to the key's project, and can never create or delete credentials (`private_api_key.*`, `sdk_key.*`). The MCP server is authorized by OAuth 2.1 with PKCE: at consent time the user picks the organization, the project and the exact subset of permissions the connection may use, and every tool call is checked against that subset intersected with the user's live permissions. A permission failure returns `403` with error code `PERM_001`.\n\n## Errors\n\nEvery non-2xx response has the same JSON body (`ErrorResponse`): `{ \"error\": { \"code\": \"AUTH_003\", \"message\": \"…\", \"details\": { … } }, \"timestamp\": \"…\" }`. `code` is a stable, machine-readable identifier (`AUTH_*`, `PERM_*`, `VAL_*`, `ORG_*`, `PROJECT_*`, …); `message` is human-readable and may change; `details` carries typed extras such as `field`, `resource` or `retryAfterSeconds`. `400` = invalid request, `401` = missing or invalid credential, `403` = credential accepted but not permitted, `404` = not found (or not visible to this credential), `409` = conflict, `429` = rate limited, `5xx` = unexpected server error.\n\n## Rate limits\n\nAuthenticated requests are limited per credential to 1,000 requests per minute (fixed window). Every response carries `RateLimit-Policy` and `RateLimit` (IETF draft-ietf-httpapi-ratelimit-headers) plus the legacy `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`; a `429` also carries `Retry-After` (seconds). Public, unauthenticated endpoints (`/public/*`) have their own stricter per-IP limits and answer `429` with `Retry-After` as well. Event ingestion (`/sdk/v1/*`, `/ingest/v1/*`) is not rate limited by this policy.\n\n## Versioning and deprecation\n\nThis is version 1 of the API (`info.version`). Paths are stable and changes are additive: new fields, parameters and endpoints may appear at any time, and clients must ignore fields they do not recognise. Breaking changes ship under a new path prefix (`/v2/…`) rather than by changing an existing operation. An operation scheduled for removal is marked `deprecated: true` in this document at least 90 days before its sunset and, during that period, every response from it carries `Deprecation` (RFC 9745), `Sunset` (RFC 8594) and a `Link: <…>; rel=\"deprecation\"` header pointing at the migration notes. Changes are announced at https://docs.kitbase.dev/changelog/.\n\n## Agents\n\n- **MCP server** (Streamable HTTP, OAuth 2.1 or private API key): https://api.kitbase.dev/mcp — server card at https://api.kitbase.dev/mcp/server-card, catalog at https://kitbase.dev/.well-known/ai-catalog.json.\n- **CLI**: `npm install -g @kitbase/cli` (https://www.npmjs.com/package/@kitbase/cli) — every operation here is also a command.\n- **llms.txt**: https://kitbase.dev/llms.txt and https://docs.kitbase.dev/llms.txt.",
    "version": "1.0.0",
    "termsOfService": "https://kitbase.dev/terms",
    "contact": {
      "name": "Kitbase support",
      "email": "support@kitbase.dev",
      "url": "https://kitbase.dev/contact"
    },
    "x-generated-by": "tools/spec/derive-openapi.mjs (derived from openapi.yaml)"
  },
  "externalDocs": {
    "description": "Kitbase API reference",
    "url": "https://docs.kitbase.dev/api-reference"
  },
  "servers": [
    {
      "url": "https://api.kitbase.dev",
      "description": "Production"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    },
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Authentication",
      "description": "User authentication and authorization operations"
    },
    {
      "name": "Organizations",
      "description": "Organization management operations"
    },
    {
      "name": "Invitations",
      "description": "Invitation management operations"
    },
    {
      "name": "Members",
      "description": "Organization members management operations"
    },
    {
      "name": "Users",
      "description": "User management operation"
    },
    {
      "name": "Roles & Permissions",
      "description": "Role and permission management operations"
    },
    {
      "name": "Projects",
      "description": "Project management operations"
    },
    {
      "name": "In-App Messages",
      "description": "In-app message and channel management"
    },
    {
      "name": "SDK Keys",
      "description": "SDK key management for build uploads"
    },
    {
      "name": "Audit Logs",
      "description": "Audit log and activity tracking operations"
    },
    {
      "name": "Notifications",
      "description": "User notification management"
    },
    {
      "name": "Webhooks",
      "description": "Webhook subscription management"
    },
    {
      "name": "Event Analytics",
      "description": "Event viewing and analytics (Dashboard)"
    },
    {
      "name": "Feature Flags",
      "description": "Feature flag management and evaluation"
    },
    {
      "name": "Feature Flag Segments",
      "description": "Feature flag targeting segment management"
    },
    {
      "name": "Funnels",
      "description": "Funnel definitions and conversion analysis"
    },
    {
      "name": "AI Visibility"
    },
    {
      "name": "Site Audit",
      "description": "One crawl, one report: a link-following crawl of the project's website, the issues it found ranked by severity, the page-by-page snapshot behind them, and the weighted AI-readiness score. Nothing here spends money at a provider — the crawler and the checks are ours, so the only cost of a run is wall-clock time.\n"
    },
    {
      "name": "Integrations"
    },
    {
      "name": "Data Import",
      "description": "Third-party integration management (Slack, etc.)"
    },
    {
      "name": "Billing",
      "description": "Billing plans, subscriptions, and usage management"
    },
    {
      "name": "Keyword Research",
      "description": "Keyword ideas with volume, difficulty, CPC and intent; saved keyword lists and tags; and organic SERP inspection. Every research, SERP and refresh call spends real money at DataForSEO, so paid operations are POST and are metered against the organization's SEO data budget.\n"
    },
    {
      "name": "SDK",
      "description": "SDK endpoints for mobile applications (API key authenticated)"
    },
    {
      "name": "CLI",
      "description": "CLI endpoints for CI/CD pipelines (private API key authenticated)"
    },
    {
      "name": "CLI Auth",
      "description": "Browser-based login flow for the Kitbase CLI (device authorization sessions)"
    },
    {
      "name": "MCP",
      "description": "The Model Context Protocol server, for AI agents."
    },
    {
      "name": "Discovery",
      "description": "Machine-readable descriptions of this API, served anonymously."
    }
  ],
  "paths": {
    "/{orgSlug}/projects/{projectId}/agent/conversations": {
      "delete": {
        "operationId": "deleteAllProjectAgentConversations",
        "summary": "Delete every conversation in this scope",
        "description": "Clears the caller's assistant history for this project (or, with workflowId, for that workflow). Permanent: the conversations and their messages are deleted, not archived. Scoped exactly like the list it clears, so a project conversation is the signed-in user's own and a workflow conversation is the one shared for that graph.",
        "tags": [
          "Project Agent"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "workflowId",
            "in": "query",
            "required": false,
            "description": "Scopes the clear to one workflow's shared conversation.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "History cleared",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/users/me": {
      "patch": {
        "operationId": "updateCurrentUser",
        "summary": "Update current user's profile",
        "description": "Updates the current user's first name and/or last name.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "User profile updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CurrentUserResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/users/me": {
      "get": {
        "operationId": "getCurrentUserWithOrgContext",
        "summary": "Get current user info with role and permissions for the specified organization",
        "description": "Returns the current user's information including their role and permissions\nfor the organization specified by the orgSlug path parameter.\nUnlike GET /users/me, this endpoint always resolves the organization context\nand populates currentOrganizationRole.\n",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "User information retrieved with role and permissions for the specified organization",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CurrentUserResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/auth/refresh-token": {
      "post": {
        "operationId": "refreshToken",
        "summary": "Refresh JWT token",
        "tags": [
          "Authentication"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshTokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token refreshed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Refresh JWT token"
      }
    },
    "/users/me/2fa/setup": {
      "post": {
        "operationId": "setupTwoFactor",
        "summary": "Initialize 2FA setup",
        "description": "Generates a new TOTP secret and backup codes for 2FA setup.\nThe user must verify a TOTP code using the enable endpoint to activate 2FA.\nCalling this endpoint again will generate new secret and codes (previous setup is discarded).\n\nCan be authenticated with either a Bearer token or a 2FA setup token (received when login\nreturns twoFactorSetupRequired: true because the user belongs to an org that requires 2FA).\n",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "X-2FA-Setup-Token",
            "in": "header",
            "required": false,
            "description": "Temporary token for 2FA setup (received from login when twoFactorSetupRequired is true)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "2FA setup initiated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorSetupResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "409": {
            "description": "2FA is already enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/users/me/2fa/enable": {
      "post": {
        "operationId": "enableTwoFactor",
        "summary": "Enable 2FA after setup",
        "description": "Verifies the TOTP code and enables 2FA for the user's account.\nMust be called after /users/me/2fa/setup.\n\nCan be authenticated with either a Bearer token or a 2FA setup token (received when login\nreturns twoFactorSetupRequired: true because the user belongs to an org that requires 2FA).\n",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "X-2FA-Setup-Token",
            "in": "header",
            "required": false,
            "description": "Temporary token for 2FA setup (received from login when twoFactorSetupRequired is true)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorEnableRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "2FA enabled successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorStatusResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid TOTP code or no pending setup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/users/me/2fa/disable": {
      "post": {
        "operationId": "disableTwoFactor",
        "summary": "Disable 2FA",
        "description": "Disables 2FA for the user's account. Requires password and current TOTP/backup code.\nWill be forbidden if the user is a member of any organization that requires 2FA.\n",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorDisableRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "2FA disabled successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorStatusResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid password or code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "description": "Cannot disable 2FA because one or more organizations require it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorDisableForbiddenResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/users/me/2fa/backup-codes": {
      "post": {
        "operationId": "regenerateBackupCodes",
        "summary": "Regenerate backup codes",
        "description": "Generates new backup codes and invalidates all previous codes.\nRequires 2FA to be enabled.\n",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "New backup codes generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BackupCodesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "2FA is not enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/users/me/2fa/status": {
      "get": {
        "operationId": "getTwoFactorStatus",
        "summary": "Get 2FA status",
        "description": "Returns the current 2FA status for the authenticated user.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "2FA status retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorStatusResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/users/me/passkeys": {
      "get": {
        "operationId": "listPasskeys",
        "summary": "List passkeys",
        "description": "Returns the authenticated user's registered passkeys.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Passkeys retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PasskeyListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/users/me/passkeys/{passkeyId}": {
      "patch": {
        "operationId": "renamePasskey",
        "summary": "Rename a passkey",
        "description": "Updates the user-friendly label of one of the authenticated user's passkeys.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "passkeyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Passkey id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PasskeyRenameRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Passkey renamed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PasskeyResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deletePasskey",
        "summary": "Delete a passkey",
        "description": "Removes one of the authenticated user's passkeys.",
        "tags": [
          "Users"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "passkeyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Passkey id"
          }
        ],
        "responses": {
          "204": {
            "description": "Passkey deleted",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/auth/cli/sessions": {
      "post": {
        "operationId": "createCliAuthSession",
        "summary": "Create a CLI login session",
        "description": "Starts a browser-based CLI login. Returns a session id, a short user code the CLI\nmust display in the terminal, a poll secret held only by the CLI, and the dashboard\nverification URL to open in the browser. Unauthenticated; rate limited per IP.\n",
        "tags": [
          "CLI Auth"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CliAuthSessionCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliAuthSessionCreateResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "description": "Too many sessions created from this IP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/auth/cli/sessions/{sessionId}": {
      "get": {
        "operationId": "getCliAuthSession",
        "summary": "Get CLI login session details (for the approval page)",
        "description": "Returns display metadata for the approval page (device name, IP, status, expiry).\nRequires an authenticated dashboard user. Never returns the user code or poll secret.\n",
        "tags": [
          "CLI Auth"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliAuthSessionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Unknown or expired session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/auth/cli/sessions/{sessionId}/approve": {
      "post": {
        "operationId": "approveCliAuthSession",
        "summary": "Approve a CLI login session",
        "description": "Approves the pending CLI session for the authenticated user. The user must supply\nthe user code displayed in their terminal (anti-phishing). After 5 wrong codes the\nsession is denied.\n",
        "tags": [
          "CLI Auth"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CliAuthSessionApproveRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session approved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliAuthSessionApproveResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid user code (AUTH_018) or session not pending (AUTH_019)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Unknown or expired session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/auth/cli/sessions/{sessionId}/deny": {
      "post": {
        "operationId": "denyCliAuthSession",
        "summary": "Deny a CLI login session",
        "tags": [
          "CLI Auth"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Session denied",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Unknown or expired session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Deny a CLI login session"
      }
    },
    "/auth/cli/sessions/{sessionId}/token": {
      "post": {
        "operationId": "pollCliAuthSessionToken",
        "summary": "Poll for CLI session tokens (CLI only)",
        "description": "Called by the CLI with its poll secret. Returns 202 while the session is pending.\nOn the first call after approval, mints access and refresh tokens (one-time; the\nsession is then consumed). Respect pollIntervalSeconds; polling faster returns 429.\n",
        "tags": [
          "CLI Auth"
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CliAuthTokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved — tokens issued (one time only)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliAuthTokenResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "202": {
            "description": "Authorization pending",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliAuthTokenPendingResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "description": "Invalid poll secret",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "403": {
            "description": "Session denied by user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "404": {
            "description": "Unknown session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "410": {
            "description": "Session expired or already consumed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "description": "Polling too fast — slow down",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/organizations": {
      "get": {
        "operationId": "listOrganizations",
        "summary": "List user's organizations",
        "description": "Returns all organizations that the authenticated user is a member of. Does not require organization context.",
        "tags": [
          "Organizations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Organizations retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/OrganizationResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createOrganization",
        "summary": "Create a new organization",
        "description": "Users can create up to 3 organizations. Does not require organization context.",
        "tags": [
          "Organizations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrganizationRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Organization created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/organizations/current": {
      "get": {
        "operationId": "getCurrentOrganization",
        "summary": "Get current organization details",
        "description": "Get organization details based on the orgSlug path parameter. User must be a member of the organization.",
        "tags": [
          "Organizations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Organization retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Organization slug is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateOrganization",
        "summary": "Update organization",
        "description": "Update organization fields. Supports partial updates (PATCH semantics) - only provided fields will be updated.\n\nUpdatable fields:\n- name: Organization display name\n- logoUrl: URL to organization logo image\n- require2fa: Whether organization requires members to have 2FA enabled\n- dataRetentionNotificationsEnabled: Whether organization receives data retention emails and in-app notifications\n\nImmutable fields (cannot be changed):\n- orgSlug: Organization slug identifier\n- created_at, created_by_user_id: Creation metadata\n\nNote: At least one field must be provided in the request. Requires Owner/Admin role or organization.update permission.\n",
        "tags": [
          "Organizations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateOrganizationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Organization updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/roles": {
      "get": {
        "operationId": "listRoles",
        "summary": "List available roles",
        "description": "Returns all global roles that can be assigned to organization members",
        "tags": [
          "Roles & Permissions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Roles retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RoleResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/roles/with-permissions": {
      "get": {
        "operationId": "listRolesWithPermissions",
        "summary": "List roles with permissions",
        "description": "Returns all roles with their associated permission codes",
        "tags": [
          "Roles & Permissions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Roles with permissions retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RoleWithPermissionsResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/invite": {
      "post": {
        "operationId": "sendInvitation",
        "summary": "Send invitation",
        "description": "Send an invitation to add a new member to the organization. Organization context determined by orgSlug path parameter. Requires Owner/Admin role.",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvitationRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invitation sent successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/invitations": {
      "get": {
        "operationId": "listPendingInvitations",
        "summary": "List pending invitations",
        "description": "List all pending, non-expired invitations addressed to the authenticated user's email.\nReturns invitations from all organizations where the user has been invited.\n",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Invitations retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvitationResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/invitations/{invitationId}/reject": {
      "post": {
        "operationId": "rejectInvitationById",
        "summary": "Reject invitation by ID",
        "description": "Reject an invitation by its ID. Used by the invitee to decline an invitation. Requires authentication.",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "invitationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Invitation ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation rejected successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid invitation state (not pending)",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Invalid token",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/invitations/{invitationId}/accept": {
      "post": {
        "operationId": "acceptInvitation",
        "summary": "Accept invitation and join organization",
        "description": "Accept an invitation and join the organization. Requires authentication.\n",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "invitationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Invitation ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation accepted successfully, user is now a member",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (invitation expired or already accepted)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "expired": {
                    "value": {
                      "code": "INV_002",
                      "message": "This invitation has expired"
                    }
                  },
                  "already_accepted": {
                    "value": {
                      "code": "INV_003",
                      "message": "This invitation has already been accepted"
                    }
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "description": "Forbidden (email mismatch)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "code": "INV_006",
                  "message": "This invitation is addressed to different email"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "description": "Conflict (user already member)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "code": "INV_004",
                  "message": "You are already a member of this organization"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/invitations/accept/{token}": {
      "post": {
        "operationId": "acceptInvitationByToken",
        "summary": "Accept invitation by token",
        "description": "Accept invitation using token from email link. Requires authentication.",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Invitation token from email"
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation accepted, user joined organization",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid invitation state (expired/already accepted)",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Invalid token",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "409": {
            "description": "User already member",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/invitations/reject/{token}": {
      "post": {
        "operationId": "rejectInvitationByToken",
        "summary": "Reject invitation by token",
        "description": "Reject invitation using token from email link. Requires authentication. Updates status to canceled.",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Invitation token from email"
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation rejected successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid invitation state (not pending)",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Invalid token",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/invitations/{identifier}": {
      "get": {
        "operationId": "getInvitation",
        "summary": "Get invitation by ID or token",
        "description": "Retrieve an invitation by ID or token. Must belong to authenticated user.\nUse query parameter 'type' to specify lookup method:\n- type=id (default): lookup by invitation ID\n- type=token: lookup by invitation token\n",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "identifier",
            "in": "path",
            "required": true,
            "description": "Invitation ID or token",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Lookup method (id or token)",
            "schema": {
              "type": "string",
              "enum": [
                "id",
                "token"
              ],
              "default": "id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "description": "Invitation not addressed to user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/invitations/{invitationId}": {
      "delete": {
        "operationId": "deleteInvitation",
        "summary": "Delete a pending invitation",
        "description": "Delete a pending invitation. Used by organization admins.",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "invitationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Invitation ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Invitation deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invitation is not in pending status",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateInvitation",
        "summary": "Update invitation role",
        "description": "Update the role of a pending invitation. Only pending invitations can be updated.\nRequires member.invite permission.\n",
        "tags": [
          "Invitations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "invitationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Invitation ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateInvitationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invitation updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (e.g., invitation not pending, invalid role)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "notPending": {
                    "summary": "Invitation not pending",
                    "value": {
                      "error": {
                        "code": "INV_007",
                        "message": "Cannot update invitation that is not in pending status"
                      }
                    }
                  },
                  "ownerRole": {
                    "summary": "Cannot assign owner role",
                    "value": {
                      "error": {
                        "code": "VAL_001",
                        "message": "Cannot assign 'owner' role via invitation"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/members": {
      "get": {
        "operationId": "listOrganizationMembers",
        "summary": "List organization members",
        "description": "List all members of the organization. Organization context determined by orgSlug path parameter. Any member can view.",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number (0-based)",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Number of items per page",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Members and invitations retrieved successfully (merged and sorted by timestamp)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedMemberOrInvitationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/members/{membershipId}": {
      "patch": {
        "operationId": "updateMemberRole",
        "summary": "Update member role",
        "description": "Update a member's role. Organization context determined by orgSlug path parameter. Requires Owner/Admin role.",
        "tags": [
          "Members/member"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "membershipId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Membership ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMemberRoleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Member role updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrganizationMemberResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "removeMember",
        "summary": "Remove member",
        "description": "Remove a member from the organization. Organization context determined by orgSlug path parameter. Requires Owner/Admin role. Owner cannot remove themselves.",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "membershipId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Membership ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Member removed successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List projects",
        "description": "List all projects for the organization. Organization context determined by orgSlug path parameter. Any member can view.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Projects retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProjectResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createProject",
        "summary": "Create project",
        "description": "Create a new project. Organization context determined by orgSlug path parameter. Requires Developer+ role.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProjectRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Project created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}": {
      "get": {
        "operationId": "getProject",
        "summary": "Get project details",
        "description": "Get project details. Organization context determined by orgSlug path parameter. Any member can view.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          }
        ],
        "responses": {
          "200": {
            "description": "Project retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateProject",
        "summary": "Update project",
        "description": "Update project. Organization context determined by orgSlug path parameter. Requires Developer+ role.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProjectRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Project updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteProject",
        "summary": "Delete project",
        "description": "Delete project. Organization context determined by orgSlug path parameter. Requires Developer+ role.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          }
        ],
        "responses": {
          "204": {
            "description": "Project deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/settings": {
      "get": {
        "operationId": "getProjectSettings",
        "summary": "Get project settings",
        "description": "Get project data-collection settings. Organization context determined by orgSlug path parameter. Any member can view.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          }
        ],
        "responses": {
          "200": {
            "description": "Project settings retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectSettingsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateProjectSettings",
        "summary": "Update project settings",
        "description": "Update project data-collection settings. Only provided fields are changed. Requires Developer+ role.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProjectSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Project settings updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectSettingsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/analytics": {
      "get": {
        "operationId": "getProjectAnalytics",
        "summary": "Get project analytics",
        "description": "Get analytics data for a project including event metrics and storage usage.\n- Events data (total events and unique users) is filtered by the from/to date range\n- Total build size is calculated for all builds regardless of time period\nOrganization context determined by orgSlug path parameter.\n",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          },
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD), in the project's reporting timezone"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD), in the project's reporting timezone"
          }
        ],
        "responses": {
          "200": {
            "description": "Project analytics retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectAnalyticsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/brands": {
      "get": {
        "operationId": "listAiVisibilityBrands",
        "summary": "List AI visibility brands",
        "description": "List the project's tracked brands (self brand and competitors) with their aliases.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Brands retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityBrandResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createAiVisibilityBrand",
        "summary": "Create AI visibility brand",
        "description": "Create a tracked brand. Only one self brand (isSelf=true) is allowed per project.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityBrandRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Brand created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityBrandResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/brands/{brandId}": {
      "put": {
        "operationId": "updateAiVisibilityBrand",
        "summary": "Update AI visibility brand",
        "description": "Update a tracked brand and replace its alias list.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "brandId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityBrandRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Brand updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityBrandResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteAiVisibilityBrand",
        "summary": "Delete AI visibility brand",
        "description": "Delete a tracked brand, its aliases, and its historical mentions.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "brandId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Brand deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/prompts/suggest": {
      "post": {
        "operationId": "suggestAiVisibilityPrompts",
        "summary": "Suggest prompts from a brand name",
        "description": "Asks a configured AI provider to generate candidate buyer-intent search prompts for a brand, given just its name (and optionally its domain). Suggestions are returned for review — nothing is persisted; add the ones you want via the bulk-create prompts endpoint. Costs one small provider call (the cheapest enabled provider is used); fails clearly if no provider is configured or the organization is over its monthly budget.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPromptSuggestionsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Suggestions generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPromptSuggestionsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/topics": {
      "get": {
        "operationId": "listAiVisibilityTopics",
        "summary": "List prompt topics",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "includeArchived",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Topics retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityTopicResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "List prompt topics"
      },
      "post": {
        "operationId": "createAiVisibilityTopic",
        "summary": "Create a prompt topic",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityTopicRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Topic created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityTopicResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Create a prompt topic"
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/topics/backfill": {
      "post": {
        "operationId": "backfillAiVisibilityTopics",
        "summary": "Apply current topic assignments to legacy runs",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityTopicBackfillRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Backfill preview or result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityTopicBackfillResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Apply current topic assignments to legacy runs"
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/topics/{topicId}": {
      "put": {
        "operationId": "updateAiVisibilityTopic",
        "summary": "Rename a prompt topic",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityTopicRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Topic updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityTopicResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Rename a prompt topic"
      },
      "delete": {
        "operationId": "deleteAiVisibilityTopic",
        "summary": "Archive a prompt topic",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "topicId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Topic archived",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Archive a prompt topic"
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/topics-breakdown": {
      "get": {
        "operationId": "getAiVisibilityTopicsBreakdown",
        "x-aivis-analytics-read": "aggregate",
        "x-aivis-filter-exempt": {
          "topics": "the response is already one row per topic; callers drop rows client-side"
        },
        "summary": "Per-topic visibility and share of voice",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            }
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Topic breakdown retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityTopicsBreakdownResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Per-topic visibility and share of voice"
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/personas": {
      "get": {
        "operationId": "listAiVisibilityPersonas",
        "summary": "List buyer personas",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "includeArchived",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Personas retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityPersonaResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "List buyer personas"
      },
      "post": {
        "operationId": "createAiVisibilityPersona",
        "summary": "Create a buyer persona",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPersonaRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Persona created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPersonaResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Create a buyer persona"
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/personas/backfill": {
      "post": {
        "operationId": "backfillAiVisibilityPersonas",
        "summary": "Apply current persona assignments to legacy runs",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPersonaBackfillRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Backfill preview or result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPersonaBackfillResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Apply current persona assignments to legacy runs"
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/personas/suggest": {
      "post": {
        "operationId": "suggestAiVisibilityPersonas",
        "summary": "Draft candidate buyer personas",
        "description": "Drafts 2-3 personas from the brand name and domain. Nothing is persisted: the drafts are returned for the caller to edit and save through the create endpoint, because an unreviewed auto-generated persona is reliably too broad to change which prompts get written.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPersonaSuggestionsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persona drafts generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPersonaSuggestionsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/personas/{personaId}": {
      "put": {
        "operationId": "updateAiVisibilityPersona",
        "summary": "Update a buyer persona",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "personaId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPersonaRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persona updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPersonaResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Update a buyer persona"
      },
      "delete": {
        "operationId": "deleteAiVisibilityPersona",
        "summary": "Archive a buyer persona",
        "description": "Archiving unassigns the persona from its prompts. Historical runs keep their snapshotted persona, so past reporting is unchanged.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "personaId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Persona archived",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/personas-breakdown": {
      "get": {
        "operationId": "getAiVisibilityPersonasBreakdown",
        "x-aivis-analytics-read": "aggregate",
        "x-aivis-filter-exempt": {
          "topics": "persona and topic are independent groupings of the same runs; this read groups by persona and callers scope topics with their own breakdown\n"
        },
        "summary": "Per-persona visibility and share of voice",
        "description": "One row per persona, plus a row for prompts with no persona. Because a prompt has exactly one persona, every run lands in exactly one row — so these shares are directly summable, unlike a tag-style grouping where a run counted under several personas would double-count.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            }
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Persona breakdown retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPersonasBreakdownResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/prompts": {
      "get": {
        "operationId": "listAiVisibilityPrompts",
        "summary": "List AI visibility prompts",
        "description": "List the project's tracked prompts (active and inactive).",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Prompts retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityPromptResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createAiVisibilityPrompts",
        "summary": "Create AI visibility prompts (bulk)",
        "description": "Create one or more tracked prompts in a single call.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAiVisibilityPromptsRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Prompts created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityPromptResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/prompts/bulk-move": {
      "post": {
        "operationId": "bulkMoveAiVisibilityPrompts",
        "summary": "Move AI visibility prompts to a topic (bulk)",
        "description": "Re-assigns every listed prompt to one topic in a single transaction. All or nothing: an unknown prompt id, or a topic that is not an active topic of this project, fails the whole call and moves nothing.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPromptBulkMoveRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Prompts moved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPromptBulkResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/prompts/bulk-assign-persona": {
      "post": {
        "operationId": "bulkAssignAiVisibilityPromptPersona",
        "summary": "Assign a persona to AI visibility prompts (bulk)",
        "description": "Assigns one persona to every listed prompt in a single transaction, or unassigns them all when `personaId` is null. All or nothing: an unknown prompt id, or a persona that is not an active persona of this project, fails the whole call and assigns nothing. Prompts already carrying the destination persona are skipped, so re-running the call is quiet rather than filling the audit trail with changes that did not happen.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPromptBulkAssignPersonaRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Personas assigned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPromptBulkResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/prompts/bulk-delete": {
      "post": {
        "operationId": "bulkDeleteAiVisibilityPrompts",
        "summary": "Delete AI visibility prompts (bulk)",
        "description": "Permanently deletes every listed prompt in a single transaction. Their runs and computed metrics go with them, so periods that included them lose their contribution to the aggregates. All or nothing: an unknown prompt id fails the whole call and deletes nothing. To stop prompts from running while keeping their history, set `active: false` via PUT instead.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPromptBulkDeleteRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Prompts deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPromptBulkResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/prompts/{promptId}": {
      "put": {
        "operationId": "updateAiVisibilityPrompt",
        "summary": "Update AI visibility prompt",
        "description": "Replaces the prompt's own fields — text, intent tier, locale, and whether it runs. It leaves the prompt's topic and persona exactly as they were; move those with `prompts/bulk-move` and `prompts/bulk-assign-persona`, which accept a single id.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "promptId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityPromptUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Prompt updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPromptResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteAiVisibilityPrompt",
        "summary": "Delete AI visibility prompt",
        "description": "Permanently deletes a prompt. Its runs and computed metrics are deleted with it, so periods that included it lose its contribution to the aggregates. To stop a prompt from running while keeping its history, set `active: false` via PUT instead.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "promptId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Prompt deleted",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/jobs/estimate": {
      "get": {
        "operationId": "getAiVisibilityJobEstimate",
        "summary": "Estimate cost of an analysis run",
        "description": "Pre-run cost estimate (active prompts x enabled providers) plus current month-to-date spend against the budget cap.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Estimate computed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityJobEstimateResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/providers": {
      "get": {
        "operationId": "getAiVisibilityProviders",
        "summary": "AI engines available to this organization",
        "description": "The AI search engines this project can run and display, resolved server-side: the engines configured on the server intersected with the organization's plan (billing feature ai_visibility_providers). Clients must use this list — not a hardcoded one — when rendering engine filters, so plans that exclude engines never surface them in the UI.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Available engines retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityProvidersResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/regions": {
      "get": {
        "operationId": "getAiVisibilityRegions",
        "summary": "Regions this project is measured from",
        "description": "The geographic vantage points this project's prompts are asked from, resolved server-side from the organization's `ai_visibility_regions` entitlement (hidden, granted by support). Always contains US. Each entry carries the countries the region covers, for display. Read-only — the customer does not choose these. Clients render the region filter only when more than one region is returned, and never derive entitlement themselves.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Regions retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityRegionsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/schedule": {
      "get": {
        "operationId": "getAiVisibilitySchedule",
        "summary": "Automatic analysis schedule and time until the next run",
        "description": "State of the automatic analysis schedule for this project: whether auto-run is enabled (organizations with an active paid subscription get one automatic run every 24 hours), when the next run is due, and whether a manual run is currently allowed (suspended organizations get a single free analysis before an upgrade is required).\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityScheduleResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/jobs": {
      "get": {
        "operationId": "listAiVisibilityJobs",
        "summary": "List AI visibility analysis jobs",
        "description": "Job history for the project, newest first.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Jobs retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityJobResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "startAiVisibilityJob",
        "summary": "Start an AI visibility analysis job",
        "description": "Starts a resumable analysis job querying every enabled AI provider with every active prompt. Rejected when configuration is incomplete, another job is active, or the monthly budget cap would be exceeded. The job runs in the background; poll the job resource for progress.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "201": {
            "description": "Job started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityJobResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/jobs/{jobId}": {
      "get": {
        "operationId": "getAiVisibilityJob",
        "summary": "Get AI visibility job with live progress",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityJobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityJobResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Get AI visibility job with live progress"
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/jobs/{jobId}/runs": {
      "get": {
        "operationId": "listAiVisibilityJobRuns",
        "x-aivis-analytics-read": "detail",
        "summary": "List a job's runs",
        "description": "One row per (prompt x provider) unit, for drill-down into individual AI answers.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityJobId"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Runs retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityRunSummary"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/jobs/{jobId}/pause": {
      "post": {
        "operationId": "pauseAiVisibilityJob",
        "summary": "Pause a running job",
        "description": "Requests a pause; the job settles to PAUSED after its current unit batch. Completed units are preserved.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityJobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Pause requested",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityJobResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/jobs/{jobId}/resume": {
      "post": {
        "operationId": "resumeAiVisibilityJob",
        "summary": "Resume a paused job",
        "description": "Resumes from the remaining pending units — completed provider calls are never re-executed or re-billed.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityJobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Job resumed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityJobResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/jobs/{jobId}/cancel": {
      "post": {
        "operationId": "cancelAiVisibilityJob",
        "summary": "Cancel an active job",
        "description": "Cancels a running or paused job. Results of already-completed units are kept.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityJobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Cancellation requested",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityJobResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/visibility": {
      "get": {
        "operationId": "getAiVisibilitySeries",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Presence-rate time series",
        "description": "One data point per completed analysis job, oldest first.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 30
            },
            "description": "Maximum number of most recent jobs to include (ignored when from/to set)"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Series retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilitySeriesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/domains": {
      "get": {
        "operationId": "getAiVisibilityDomains",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Cited-domain map",
        "description": "Domains cited by AI answers, aggregated over the most recent completed jobs and classified SELF / COMPETITOR / OTHER.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 25
            },
            "description": "Maximum number of domains to return"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Domain map retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityDomainsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/domains/{domain}/citations": {
      "get": {
        "operationId": "getAiVisibilityDomainCitations",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Cited URLs for one domain",
        "description": "Basic info about a single cited domain (classification, source type, totals, engines) plus a\npaginated list of the actual cited URLs under it, aggregated over the same job window as the\ncited-domain map. Powers the domain drill-in on the Citations page.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Normalized (registrable) domain, e.g. reddit.com"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Zero-based page index of the URL list"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size of the URL list"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Domain citation detail retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityDomainCitationsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/citations/pages": {
      "get": {
        "operationId": "getAiVisibilityCitedPages",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Cited pages",
        "description": "Flat, paginated list of the exact pages (URLs) AI engines cited, across all domains,\naggregated over the same job window as the cited-domain map. With `mentioningBrand=true`\nonly citations from answers that featured the project's own brand (a brand mention or a\ncitation of the brand's domain) are counted — i.e. the pages behind the answers that\ntalk about the brand.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "mentioningBrand",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, only count citations from answers where the project's own brand appeared"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Zero-based page index of the URL list"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size of the URL list"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Cited pages retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityCitedPagesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/breakdown": {
      "get": {
        "operationId": "getAiVisibilityBreakdown",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Per-provider breakdown",
        "description": "Presence and citation totals per AI provider aggregated over the most recent completed jobs.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Breakdown retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityBreakdownResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/paid-placements": {
      "get": {
        "operationId": "getAiVisibilityPaidPlacements",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Sponsored placements inside AI answers",
        "description": "Who is buying ad slots inside the AI answers for this project's prompts, and on which prompts. Read from the SERP responses the tracked engines already return, so it costs nothing extra to collect.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          }
        ],
        "responses": {
          "200": {
            "description": "Paid placements retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPaidPlacementsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/competitors": {
      "get": {
        "operationId": "getAiVisibilityCompetitors",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Competitors leaderboard",
        "description": "Every tracked brand (the project's own brand plus every competitor) ranked by visibility rate, aggregated over the most recent completed jobs — the same presence rule used for the project's own brand (mention or domain citation), generalized to all of them so they can be compared directly.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 25
            },
            "description": "Maximum number of brands to return"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Competitors retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityCompetitorsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/discovered-competitors": {
      "get": {
        "operationId": "getAiVisibilityDiscoveredCompetitors",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Suggested (untracked) competitors",
        "description": "Brands the AI named organically across the most recent completed jobs that are NOT yet tracked (neither the project's own brand nor a tracked competitor), ranked by how many runs mentioned each — the suggestion feed for \"track this competitor\". Extracted during the analysis pass, so only runs analyzed with discovery enabled contribute.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 25
            },
            "description": "Maximum number of suggested competitors to return"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Suggested competitors retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityDiscoveredCompetitorsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/share-of-voice": {
      "get": {
        "operationId": "getAiVisibilityShareOfVoice",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Share-of-voice over time",
        "description": "Per completed job (oldest first), each tracked brand's normalized share of voice (its runsWithBrand divided by the sum across all brands) and dense rank, for one AI provider.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to include (ignored when from/to set)"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Share of voice retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityShareOfVoiceResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/provider-series": {
      "get": {
        "operationId": "getAiVisibilityProviderSeries",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Per-provider presence time series",
        "description": "Per completed job (oldest first), one entry per AI provider (the 'ALL' rollup is excluded) for the project's own brand — presence and citation counts plus mention/citation rates. Powers the per-provider trend line chart.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 30
            },
            "description": "Maximum number of most recent jobs to include (ignored when from/to set)"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Provider series retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityProviderSeriesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/competitor-series": {
      "get": {
        "operationId": "getAiVisibilityCompetitorSeries",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Per-competitor presence time series",
        "description": "Per completed job (oldest first), one entry per tracked brand (the project's own brand plus every competitor) for one AI provider — presence/citation metrics plus each brand's normalized share of voice within the job. Powers the per-competitor trend line chart.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 30
            },
            "description": "Maximum number of most recent jobs to include (ignored when from/to set)"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          }
        ],
        "responses": {
          "200": {
            "description": "Competitor series retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityCompetitorSeriesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/prompts-breakdown": {
      "get": {
        "operationId": "getAiVisibilityPromptsBreakdown",
        "x-aivis-analytics-read": "aggregate",
        "summary": "Per-prompt breakdown",
        "description": "Each prompt's presence (and analysis) metrics aggregated over the most recent completed jobs, with an overall rollup plus one cell per AI provider.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "jobs",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed jobs to aggregate (ignored when from/to set)"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityPreset"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityFrom"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTo"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityTopicFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityRegionFilter"
          },
          {
            "$ref": "#/components/parameters/AiVisibilityProvider"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Prompts breakdown retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityPromptsBreakdownResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/runs/{runId}": {
      "get": {
        "operationId": "getAiVisibilityRun",
        "summary": "Run drill-down",
        "description": "Full detail of one provider call — answer text, citations, and detected brand mentions.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "runId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Run retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityRunDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/exploration-providers": {
      "get": {
        "operationId": "getAiVisibilityExplorationProviders",
        "summary": "Engines Prompt Explorer can run right now",
        "description": "The engines an ad-hoc exploration can actually be executed against: the server's configured SYNCHRONOUS adapters intersected with the organization's `ai_visibility_exploration_providers` plan value. Distinct from `/ai-visibility/providers`, which answers a tracking question and may include async consumer surfaces the synchronous exploration path cannot execute. Clients must render the engine picker from this list; an empty list means the plan grants no exploration engines and the form should be disabled.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Executable exploration engines retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityExplorationProvidersResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/explorations": {
      "get": {
        "operationId": "listAiVisibilityExplorations",
        "summary": "Recent explorations",
        "description": "This project's exploration history, newest first — shared across the project's users, unlike a browser-local recent list. Summaries only; fetch one by id for its answers. Explorations older than the retention window are pruned server-side.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Explorations retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AiVisibilityExplorationSummary"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createAiVisibilityExploration",
        "summary": "Ask one question across several engines",
        "description": "Runs one ad-hoc prompt against 1–4 engines synchronously and returns every answer, its citations, and — when `analyze` is on — the tracked brands each answer named. The prompt is NOT added to the tracked set and the answers never enter share-of-voice or any other measurement; use `POST /ai-visibility/prompts` to promote a question you want monitored.\n\nThis spends real money on every call. Engines are billed against the organization's monthly provider budget, an identical question reuses its cached answers for 7 days unless `runFresh` is set, and a per-organization daily exploration cap applies on top of the monthly budget. Engines settle independently: a busy or broken engine comes back as a FAILED row while its siblings return their answers, so a 201 does not mean every engine answered.",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiVisibilityExplorationRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Exploration executed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityExplorationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/ai-visibility/explorations/{explorationId}": {
      "get": {
        "operationId": "getAiVisibilityExploration",
        "summary": "One exploration with every answer",
        "description": "Re-opens a stored exploration exactly as it was returned, including which answers were served from cache. Nothing is re-executed and nothing is re-paid.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "explorationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Exploration retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiVisibilityExplorationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteAiVisibilityExploration",
        "summary": "Remove an exploration from history",
        "description": "Deletes the exploration and its answers for everyone in the project. Other explorations that copied one of its answers keep working — they hold their own copy, and `cacheSourceRunId` is provenance rather than a reference.\n",
        "tags": [
          "AI Visibility"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "explorationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Exploration deleted",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/characters": {
      "get": {
        "operationId": "listAgentCharacters",
        "summary": "List the characters this project can run",
        "description": "The ones we ship and the ones written here, in one list. Internal characters come back with a null systemPrompt. Requires 'workflow.view'.\n",
        "tags": [
          "Agent Characters"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "The characters available here",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentCharacterListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/characters/{characterId}/run": {
      "post": {
        "operationId": "runAgentCharacter",
        "summary": "Have a character read something now",
        "description": "Runs one character against a page, or against whatever you ask it. Costs AI credits, so it requires 'workflow.manage' rather than view. Returns 204 when no AI provider is configured or the character had nothing to say.\n",
        "tags": [
          "Agent Characters"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "characterId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunAgentCharacterRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What the character said",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentCharacterRunResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "204": {
            "description": "No provider configured, or nothing to say",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-spec/docs": {
      "get": {
        "operationId": "listSpecDocs",
        "summary": "List the planning documents this site is graded against",
        "description": "The approved plan, messaging or build standard a project has uploaded. Without one, every check grades the site against what it says about itself; with one, findings can say \"this is not what you approved\". Requires siteaudit.view.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "The project's planning documents",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpecDocsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "uploadSpecDoc",
        "summary": "Upload a planning document",
        "description": "Stores the document and reads the requirements it sets, using the organization's configured model. Extracted rules are NOT enforced until a person approves each one: a wrong rule mis-grades the whole site against a requirement nobody set, and it does it silently. Text and Markdown in v1. Requires siteaudit.manage, since extraction spends AI budget.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadSpecDocRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The document, with the rules read from it awaiting review",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpecDocResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-spec/rules": {
      "get": {
        "operationId": "listSpecRules",
        "summary": "List the rules read from the planning documents",
        "description": "Each rule beside the sentence it was read from, so a reviewer can approve or reject it in seconds. Only APPROVED rules are ever graded against. Requires siteaudit.view.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "EXTRACTED",
                "APPROVED",
                "REJECTED"
              ]
            },
            "description": "Omit for all"
          }
        ],
        "responses": {
          "200": {
            "description": "The project's rules",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpecRulesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-spec/rules/{ruleId}": {
      "patch": {
        "operationId": "reviewSpecRule",
        "summary": "Approve, reject or correct one rule",
        "description": "Approving is what lets a rule grade the site. Editing one re-approves it — the person changing it is the one vouching for it. Requires siteaudit.manage.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "ruleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReviewSpecRuleRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Recorded",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks": {
      "get": {
        "operationId": "listBacklinkSources",
        "summary": "List detected backlink sources",
        "description": "Referring domains detected from real traffic (search engines, social networks, AI assistants and self-referrals excluded), with live session counts for the selected window. Requires backlinks.view permission.\n",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Zero-based page index"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Number of sources per result page (1–200)"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "first_seen",
                "sessions"
              ],
              "default": "first_seen"
            },
            "description": "Sort by discovery recency or by referred sessions in the window"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "active",
                "ignored",
                "lost",
                "untapped"
              ],
              "default": "all"
            },
            "description": "Server-side filter. all/active/ignored list traffic-detected sources and select on the stored curation status. lost and untapped are a separate axis reading the link graph instead: lost returns every domain the graph reports as no longer linking regardless of curation status, ordered most-recently-lost first; untapped returns live graph domains that have never referred a session — links that exist but have not driven traffic yet — ordered by authority. Both include domains with a null id and no first/last seen (nothing to curate).\n"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive substring match on the domain"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 365,
              "default": 30
            },
            "description": "Window in days for the live session counts"
          }
        ],
        "responses": {
          "200": {
            "description": "Backlink sources retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BacklinkSourcesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks/{backlinkId}": {
      "patch": {
        "operationId": "updateBacklinkSource",
        "summary": "Update a backlink source's status",
        "description": "Dismiss a source as noise (ignored) or restore it (active). Requires backlinks.manage permission.",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "backlinkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Backlink source ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBacklinkSourceRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Backlink source updated",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks/detail": {
      "get": {
        "operationId": "getBacklinkSourceDetail",
        "summary": "Drill into one backlink source",
        "description": "Daily referred-session timeline, landing paths and the distinct verbatim referrer URLs (the linking pages) for one referring domain. Requires backlinks.view permission.\n",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Normalized referring host as returned by the list endpoint"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 365,
              "default": 30
            },
            "description": "Window in days for the timeline and landing paths"
          }
        ],
        "responses": {
          "200": {
            "description": "Backlink source detail retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BacklinkSourceDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks/reclamation": {
      "get": {
        "operationId": "getBacklinkReclamation",
        "summary": "Dead pages still receiving referred traffic",
        "description": "Externally referred sessions landing on pages the site crawler recorded as broken (non-2xx) — existing backlinks recoverable with a redirect. Returns siteIndexAvailable=false when the project has never indexed its site content. Requires backlinks.view permission.\n",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 365,
              "default": 90
            },
            "description": "Window in days for referred-session counts"
          }
        ],
        "responses": {
          "200": {
            "description": "Reclamation candidates retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BacklinkReclamationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks/opportunities": {
      "get": {
        "operationId": "getBacklinkOpportunities",
        "summary": "AI-cited domains to seek links from",
        "description": "Third-party (non-self, non-competitor) domains cited by AI answers for this project's prompts, aggregated over the most recent completed AI-visibility jobs and ranked by how often they appear in prompts where the brand is absent. Requires backlinks.view permission.\n",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "jobs",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of most recent completed AI-visibility jobs to aggregate"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 200
            },
            "description": "Maximum number of domains to return. Clamped to 1..200 server-side; `totalDomains` in the response says how many candidates there were before the cut.\n"
          }
        ],
        "responses": {
          "200": {
            "description": "Link opportunities retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BacklinkOpportunitiesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks/competitor-gap": {
      "get": {
        "operationId": "getBacklinkCompetitorGap",
        "summary": "Domains linking to competitors but not to you",
        "description": "The link gap computed by the last refresh, ranked by how many tracked competitors each domain links to and then by domain authority. The competitor set is resolved server-side from the AI-visibility brand directory. Requires backlinks.view permission.\n",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Maximum number of gap domains to return"
          },
          {
            "name": "competitor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Narrow the list to sources linking to this one competitor domain. Must be one of the values in the response's competitors array — anything else simply matches nothing. Case-insensitive.\n"
          }
        ],
        "responses": {
          "200": {
            "description": "Competitor link gap retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BacklinkCompetitorGapResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks/links": {
      "get": {
        "operationId": "listBacklinkLinks",
        "summary": "Exact backlinks pointing at the site",
        "description": "The individual linking pages stored by the last link-graph refresh — each row is one exact link (linking page URL, linked page, anchor, dofollow, rank and spam score), ordered by link rank. A bounded snapshot: the refresh stores the top links by rank, one per referring domain and anchor. Requires backlinks.view permission.\n",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Zero-based page index"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Page size"
          },
          {
            "name": "domain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Narrow the list to links from this one referring domain. Case-insensitive."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Substring match on the linking page URL or anchor text"
          }
        ],
        "responses": {
          "200": {
            "description": "Exact backlinks retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BacklinkLinksResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/backlinks/synced-data": {
      "delete": {
        "operationId": "deleteBacklinkSyncedData",
        "summary": "Delete synced link-graph data",
        "description": "Removes everything the DataForSEO sync has stored for this project — the profile summary, the referring-domain snapshot, the exact-link list and the competitor gap. Traffic-derived backlink sources (referrers that actually sent sessions) are first-party analytics and are NOT touched. Data returns on the next refresh, manual or scheduled. Fails with 409 while a refresh is running. Requires backlinks.manage permission.\n",
        "tags": [
          "Backlinks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Synced link-graph data deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteBacklinkSyncedDataResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/keyword-markets": {
      "get": {
        "operationId": "listKeywordMarkets",
        "summary": "Supported keyword research markets",
        "description": "Every country keyword research can be run in, with the languages DataForSEO serves there and which API answers for it. Google-Ads-served markets return no keyword difficulty or search intent, and the picker uses that flag rather than a client-side copy of the country table.\n\nOrganization-scoped rather than project-scoped on purpose: the create-project form needs this list before a project exists. It is public configuration and performs no paid call, so any organization member may read it.\n",
        "tags": [
          "Keyword Research"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Markets retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordMarketsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/keywords/research": {
      "post": {
        "operationId": "researchKeywords",
        "summary": "Research keyword ideas",
        "description": "Keyword ideas for one seed, with monthly search volume, CPC, competition, ranking difficulty and search intent.\n\n**This spends money.** A cache hit (24h, shared across the whole install because search volumes are public data) costs nothing and is returned with `fromCache: true` and the age of the answer. A miss calls DataForSEO: one call for an explicit mode, and up to THREE for `auto`, which walks related → suggestions → ideas until it has enough non-seed keywords. Use `POST .../keywords/estimate` first if the caller needs to know the range.\n\nPOST rather than GET deliberately: a paid GET is exposed to browser prefetch, proxy retries and link previews, any of which would buy results nobody asked for.\n\nFails with 400 when the server has no DataForSEO credentials, when the country or country/language combination is unsupported, or when the organization's monthly SEO data budget is exhausted; 429 when the provider's account-wide rate limit is saturated. Requires keywords.manage permission.\n",
        "tags": [
          "Keyword Research"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResearchKeywordsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Keyword ideas retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordResearchResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "description": "The keyword data provider's account-wide rate limit is saturated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/keywords/serp": {
      "post": {
        "operationId": "getKeywordSerp",
        "summary": "Inspect the organic SERP for a keyword",
        "description": "Who currently ranks on page one for a keyword in a market, with each result's estimated traffic value and backlink profile.\n\n**This spends money** on a miss (cached 12h globally — rankings are the same page for every customer who asks). An empty `items` with `reason: no_organic_results` is a real answer and is cached as one.\n\nPOST for the same reason as research: never let a prefetch or a proxy retry buy a SERP. Clients must not prefetch this on hover or retry it automatically. Requires keywords.manage permission.\n",
        "tags": [
          "Keyword Research"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KeywordSerpRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SERP retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordSerpResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "description": "The keyword data provider's account-wide rate limit is saturated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/keywords/saved": {
      "get": {
        "operationId": "listSavedKeywords",
        "summary": "List saved keywords",
        "description": "The project's saved keyword list, joined to whatever metrics are cached for each keyword's market. Free — it reads nothing from the provider, so a metric that has never been fetched is null rather than bought.\n\nFilters, ranges and sort are applied in SQL and are the same ones the CSV export accepts, so an export always covers exactly what the table showed. Requires keywords.view permission.\n",
        "tags": [
          "Keyword Research"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Zero-based page index"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 250,
              "default": 50
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Substring match on the keyword"
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "maxItems": 20
            },
            "description": "Keep only keywords containing every one of these terms"
          },
          {
            "name": "exclude",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "maxItems": 20
            },
            "description": "Drop keywords containing any of these terms"
          },
          {
            "name": "minVolume",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "maxVolume",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "minCpc",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "maxCpc",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "minDifficulty",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "maxDifficulty",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "tagIds",
            "in": "query",
            "required": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Keep keywords carrying any of these tags"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/SavedKeywordSortEnum"
            }
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Saved keywords retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSavedKeywordResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "saveKeywords",
        "summary": "Save keywords to the project",
        "description": "Adds keywords to the project's list. Free: pass the metrics the caller already holds (from a research result) in `metrics` and the save stores them without re-buying anything. Keywords already on the list are ignored rather than rejected.\n\nThe same endpoint is the destination for \"save to keywords\" actions elsewhere in the product, so it is not research-specific. Requires keywords.manage permission.\n",
        "tags": [
          "Keyword Research"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveKeywordsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Keywords saved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SaveKeywordsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/imports": {
      "get": {
        "operationId": "listDataImports",
        "summary": "List data imports for a project",
        "description": "Import history for the project, newest first. Requires dataimport.view permission.",
        "tags": [
          "Data Import"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Imports retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DataImportResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "startDataImport",
        "summary": "Start a historical data import",
        "description": "Starts a resumable one-time backfill from an external analytics platform into this project, synthesizing backdated events over the requested day range. Requires a connected source (e.g. Google Analytics) and dataimport.manage permission. Rejected when another import is already running or the range overlaps an existing (non-deleted) import for the same property.\n",
        "tags": [
          "Data Import"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartDataImportRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Import started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataImportResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/imports/{importId}": {
      "get": {
        "operationId": "getDataImport",
        "summary": "Get a data import with live progress",
        "tags": [
          "Data Import"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/DataImportId"
          }
        ],
        "responses": {
          "200": {
            "description": "Import retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataImportResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Get a data import with live progress"
      }
    },
    "/{orgSlug}/projects/{projectId}/imports/{importId}/cancel": {
      "post": {
        "operationId": "cancelDataImport",
        "summary": "Cancel a running import",
        "description": "Requests cancellation; the import settles to CANCELLED after its current day-chunk. Already-imported days are preserved. Requires dataimport.manage permission.",
        "tags": [
          "Data Import"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/DataImportId"
          }
        ],
        "responses": {
          "204": {
            "description": "Cancellation requested",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/imports/{importId}/data": {
      "delete": {
        "operationId": "deleteDataImportData",
        "summary": "Delete an import's imported data",
        "description": "Removes all synthetic events and sessions this import wrote (async ClickHouse mutation — eventually consistent). The import is marked DATA_DELETED and its range becomes re-importable. Requires the import's job to be inactive and dataimport.manage permission.\n",
        "tags": [
          "Data Import"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "$ref": "#/components/parameters/DataImportId"
          }
        ],
        "responses": {
          "202": {
            "description": "Deletion submitted",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/integrations/google-analytics/properties": {
      "get": {
        "operationId": "listGa4Properties",
        "summary": "List Google Analytics properties",
        "description": "List GA4 properties the connected Google account can read. Requires integration.view permission.",
        "tags": [
          "Data Import"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Properties retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ga4PropertyListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/config": {
      "get": {
        "operationId": "getSiteAuditConfig",
        "summary": "Get site audit configuration",
        "description": "The project's website domain, which is what audits run against, plus a prefill suggestion derived from the AI-visibility self-brand when the project has no website set yet.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Configuration retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditConfigResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits": {
      "get": {
        "operationId": "listSiteAudits",
        "summary": "List site audits",
        "description": "Audit history for the project, newest first.",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audits retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SiteAuditSummaryResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "startSiteAudit",
        "summary": "Start a site audit",
        "description": "Starts a background crawl of the configured domain: crawler-access probes (robots.txt, llms.txt, sitemap, WAF behavior), a link-following crawl seeded from the homepage and the sitemap, per-page issue rules, and enrichment from the project's own bot/AI-visibility analytics. Rejected when no domain is configured or another audit is active. Poll the progress resource while it runs.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteAuditStartRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Audit started",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/latest": {
      "get": {
        "operationId": "getLatestSiteAudit",
        "summary": "Get the latest site audit with live progress",
        "description": "The project's most recent audit, whatever state it is in. `completedOnly` narrows that to the most recent run that actually finished, which is what a reader that wants a report rather than a progress bar asks for; `target` narrows it to runs of the project's own website, so an audit somebody pointed at a competitor cannot answer for it.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "completedOnly",
            "in": "query",
            "description": "Only consider audits whose job completed.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "target",
            "in": "query",
            "description": "`own` considers only audits of the project's configured website; `any` also considers audits of other sites.",
            "schema": {
              "type": "string",
              "enum": [
                "own",
                "any"
              ],
              "default": "any"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}": {
      "get": {
        "operationId": "getSiteAudit",
        "summary": "Get one site audit",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Get one site audit"
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/summary": {
      "get": {
        "operationId": "getSiteAuditSummary",
        "summary": "Get one audit's headline statistics",
        "description": "The report's tile strip: how much was crawled, how many issues by severity, how fast the site answered, and the AI-readiness score. Computed in SQL rather than from a page list, because the page list can hold thousands of rows.\n\n`availableSections` names the finding producers the counts were computed across. Every producer is readable under siteaudit.view, which this endpoint has already required.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Summary retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditSummaryStats"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/findings/groups": {
      "get": {
        "operationId": "listSiteAuditFindingGroups",
        "summary": "List an audit's findings, grouped by rule",
        "description": "One row per rule that fired, worst first, with the copy that explains it. The affected pages are fetched separately when a group is expanded — shipping them inline would put every finding on the site in one response.\n\nGroups whose source the caller may not read are omitted entirely, aggregates included.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Finding groups retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SiteAuditFindingGroup"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/findings": {
      "get": {
        "operationId": "listSiteAuditFindings",
        "summary": "List an audit's findings",
        "description": "The drill-down behind a group, and the export's source. `source` is required whenever `findingId` is supplied: rule ids collide across the catalogs, so an id on its own does not name one rule.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "CRAWL",
                "CHECKLIST",
                "PAGE_CHECK",
                "SITE_CHECK",
                "CONTENT_CHECK"
              ]
            }
          },
          {
            "name": "findingId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "severity",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "CRITICAL",
                "WARNING",
                "INFO"
              ]
            }
          },
          {
            "name": "scope",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "PAGE",
                "SITE"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Substring match on the page URL",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Findings retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSiteAuditFindings"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/pages": {
      "get": {
        "operationId": "listSiteAuditPages",
        "summary": "List an audit's crawled pages",
        "description": "The crawl snapshot, filtered and sorted server-side because it can hold thousands of rows. This is one run's snapshot; compare two audits to see what changed between them.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Substring match on the URL",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ALL",
                "OK",
                "REDIRECT",
                "BROKEN",
                "SERVER_ERROR",
                "BLOCKED",
                "MISSING"
              ],
              "default": "ALL"
            }
          },
          {
            "name": "missingAlt",
            "in": "query",
            "description": "Only pages carrying at least one image without alt text",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "indexable",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "minDepth",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "URL",
                "STATUS",
                "SPEED",
                "WORDS",
                "DEPTH"
              ],
              "default": "URL"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pages retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSiteAuditPages"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/pages/{pageId}": {
      "get": {
        "operationId": "getSiteAuditPage",
        "summary": "Get one crawled page in full",
        "description": "The drill-down behind a row of the pages list: what the crawl measured, which checklist rules the page failed and what each of them found, what a model made of the copy, and the pages nearest to it by meaning.\n\n`pageId` is the id from the pages list, and belongs to this audit — the same URL crawled again has a different id.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Page retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditPageDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/pages/{pageId}/traffic": {
      "get": {
        "operationId": "getSiteAuditPageTraffic",
        "summary": "Get one crawled page's recent human and AI traffic",
        "description": "Daily human page views and AI-crawler hits for this page's path over the recent window — live analytics beside the crawl's snapshot, so the report can say not only what the page contains but whether anyone, human or machine, is actually reading it.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Traffic series retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditPageTrafficResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/similarity": {
      "get": {
        "operationId": "getSiteAuditSimilarity",
        "summary": "Get the audit's duplicate and near-duplicate groups",
        "description": "Which pages of the crawl say the same thing, grouped rather than paired: three pages that each duplicate the next are one problem with three pages in it, and reporting them as pairs would triple the apparent count.\n\nRead from the stored vectors, so it costs nothing and is empty when the run had no embeddings model available.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Similarity retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditSimilarityResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/facts": {
      "get": {
        "operationId": "getSiteAuditFacts",
        "summary": "Get the audit's full graded checklist, passes included",
        "description": "Every site-wide check this run graded, whether it holds up or not. The findings resources can only ever list what is wrong, so this is the only place that can say \"seventeen checks ran and fifteen hold up\" — which is what turns an accusation into a measurement.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Checklist retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditFactsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/lighthouse": {
      "get": {
        "operationId": "listSiteAuditLighthouse",
        "summary": "List an audit's Lighthouse measurements",
        "description": "What each measured page costs to load, one row per page per device. The measurement run is a separate job that starts once the crawl completes, so this is empty while a crawl is still going and stays empty when no Lighthouse provider is configured.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Substring match on the URL",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "device",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ALL",
                "MOBILE",
                "DESKTOP"
              ],
              "default": "ALL"
            }
          },
          {
            "name": "band",
            "in": "query",
            "description": "Performance score band, on the same thresholds the rings use: GOOD >= 90, NEEDS_WORK >= 50, POOR below that.",
            "schema": {
              "type": "string",
              "enum": [
                "ALL",
                "GOOD",
                "NEEDS_WORK",
                "POOR"
              ],
              "default": "ALL"
            }
          },
          {
            "name": "failuresOnly",
            "in": "query",
            "description": "Only measurements the provider could not complete",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "PERFORMANCE",
                "URL",
                "LCP",
                "CLS",
                "TTFB"
              ],
              "default": "PERFORMANCE"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Measurements retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSiteAuditLighthouse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/progress": {
      "get": {
        "operationId": "getSiteAuditProgress",
        "summary": "Live progress of a running audit",
        "description": "Phase, page counts and the last few URLs crawled. Cheap enough to poll every couple of seconds while a crawl runs; settles to DONE and stops changing once it does.\n",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Progress retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteAuditProgressResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/site-audit/audits/{auditId}/cancel": {
      "post": {
        "operationId": "cancelSiteAudit",
        "summary": "Cancel a running site audit",
        "description": "Completed checks keep their results; remaining probes are abandoned.",
        "tags": [
          "Site Audit"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "auditId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Cancellation requested",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/sdk-keys": {
      "get": {
        "operationId": "getSdkKeys",
        "summary": "Get SDK keys with pagination and sorting",
        "description": "Organization context determined by orgSlug path parameter.",
        "tags": [
          "SDK Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (default 0)"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size (default 20)"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort direction by createdAt (default desc)"
          }
        ],
        "responses": {
          "200": {
            "description": "SDK keys retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSdkKeyResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (e.g., invalid sort parameter)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createSdkKey",
        "summary": "Create a new SDK key",
        "description": "Organization context determined by orgSlug path parameter.",
        "tags": [
          "SDK Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSdkKeyRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "SDK key created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SdkKeyResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/sdk-keys/{keyId}": {
      "delete": {
        "operationId": "deleteSdkKey",
        "summary": "Delete an SDK key",
        "description": "Organization context determined by orgSlug path parameter.",
        "tags": [
          "SDK Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          },
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SDK key ID"
          }
        ],
        "responses": {
          "204": {
            "description": "SDK key deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/private-api-keys": {
      "get": {
        "operationId": "getPrivateApiKeys",
        "summary": "Get private API keys with pagination",
        "description": "List private API keys for a project. Keys are project-scoped and shown as prefixes. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Private API Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-based)"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Number of items per page"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort direction by creation date"
          }
        ],
        "responses": {
          "200": {
            "description": "Private API keys retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedPrivateApiKeyResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createPrivateApiKey",
        "summary": "Create a new private API key",
        "description": "Create a new private API key for a project. The key is project-scoped (not environment-specific), only returned once and stored as a hash. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Private API Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePrivateApiKeyRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Private API key created successfully (key only shown this once)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrivateApiKeyResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/private-api-keys/{keyId}": {
      "delete": {
        "operationId": "deletePrivateApiKey",
        "summary": "Delete a private API key",
        "description": "Delete a private API key. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Private API Keys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key identifier"
          },
          {
            "name": "keyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Private API key ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Private API key deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/feature-flags": {
      "get": {
        "operationId": "listFeatureFlags",
        "summary": "List feature flags",
        "description": "List all feature flags for a project environment. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flags"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-based)"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Number of items per page"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort direction by creation date"
          }
        ],
        "responses": {
          "200": {
            "description": "Feature flags retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedFeatureFlagResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (e.g., invalid sort parameter)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createFeatureFlag",
        "summary": "Create feature flag",
        "description": "Create a new feature flag in a project environment. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flags"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFeatureFlagRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Feature flag created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (e.g., validation error)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/feature-flags/{flagKey}": {
      "get": {
        "operationId": "getFeatureFlag",
        "summary": "Get feature flag details",
        "description": "Get detailed information about a feature flag including targeting rules. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flags"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "flagKey",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Feature flag key"
          }
        ],
        "responses": {
          "200": {
            "description": "Feature flag retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateFeatureFlag",
        "summary": "Update feature flag",
        "description": "Update a feature flag's metadata and default value. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flags"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "flagKey",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Feature flag key"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFeatureFlagRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feature flag updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (e.g., validation error)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteFeatureFlag",
        "summary": "Delete feature flag",
        "description": "Delete a feature flag. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flags"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "flagKey",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Feature flag key"
          },
          {
            "name": "deleteAllEnvironments",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, delete the feature flag with the same key across all environments in the project."
          }
        ],
        "responses": {
          "204": {
            "description": "Feature flag deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/feature-flag-segments": {
      "get": {
        "operationId": "listFeatureFlagSegments",
        "summary": "List feature flag segments",
        "description": "List all targeting segments for a project environment. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flag Segments"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-based)"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Number of items per page"
          }
        ],
        "responses": {
          "200": {
            "description": "Segments retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedFeatureFlagSegmentResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createFeatureFlagSegment",
        "summary": "Create feature flag segment",
        "description": "Create a new targeting segment. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flag Segments"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFeatureFlagSegmentRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Segment created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagSegmentResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (e.g., validation error)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "409": {
            "$ref": "#/components/responses/ConflictError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/feature-flag-segments/{segmentId}": {
      "get": {
        "operationId": "getFeatureFlagSegment",
        "summary": "Get feature flag segment",
        "description": "Get a targeting segment by ID. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flag Segments"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "segmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Segment ID (UUID)"
          }
        ],
        "responses": {
          "200": {
            "description": "Segment retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagSegmentResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateFeatureFlagSegment",
        "summary": "Update feature flag segment",
        "description": "Update a targeting segment. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flag Segments"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "segmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Segment ID (UUID)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFeatureFlagSegmentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Segment updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagSegmentResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Bad request (e.g., validation error)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteFeatureFlagSegment",
        "summary": "Delete feature flag segment",
        "description": "Delete a targeting segment. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Feature Flag Segments"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "segmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Segment ID (UUID)"
          }
        ],
        "responses": {
          "204": {
            "description": "Segment deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/in-app-messages": {
      "get": {
        "operationId": "listInAppMessages",
        "summary": "List in-app messages",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Messages retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedInAppMessageResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "List in-app messages"
      },
      "post": {
        "operationId": "createInAppMessage",
        "summary": "Create in-app message",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInAppMessageRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Message created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InAppMessageResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Create in-app message"
      }
    },
    "/{orgSlug}/projects/{projectId}/in-app-messages/{messageId}": {
      "get": {
        "operationId": "getInAppMessage",
        "summary": "Get in-app message",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Message retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InAppMessageResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Get in-app message"
      },
      "put": {
        "operationId": "updateInAppMessage",
        "summary": "Update in-app message",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateInAppMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InAppMessageResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Update in-app message"
      },
      "delete": {
        "operationId": "deleteInAppMessage",
        "summary": "Delete in-app message",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Message deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Delete in-app message"
      }
    },
    "/{orgSlug}/projects/{projectId}/in-app-messages/{messageId}/views": {
      "get": {
        "operationId": "listInAppMessageViews",
        "summary": "List message views",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Views retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedInAppMessageViewResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "List message views"
      },
      "delete": {
        "operationId": "clearInAppMessageViews",
        "summary": "Clear all views for a message",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Views cleared successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deletedCount": {
                      "type": "integer"
                    }
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Clear all views for a message"
      }
    },
    "/{orgSlug}/projects/{projectId}/in-app-messages/{messageId}/views/{viewId}": {
      "delete": {
        "operationId": "deleteInAppMessageView",
        "summary": "Delete a single message view",
        "tags": [
          "In-App Messages"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "viewId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "View deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Delete a single message view"
      }
    },
    "/{orgSlug}/audit-logs": {
      "get": {
        "operationId": "getAuditLogs",
        "summary": "Get audit logs for an organization",
        "description": "Retrieve paginated audit logs with optional filtering by action, resource type, user, and date range. Organization context determined by orgSlug path parameter.",
        "tags": [
          "Audit Logs"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by action (e.g., PROJECT_CREATED)"
          },
          {
            "name": "resourceType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by resource type (e.g., PROJECT)"
          },
          {
            "name": "userId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by user ID"
          },
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Filter by start date"
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Filter by end date"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort order by created date"
          }
        ],
        "responses": {
          "200": {
            "description": "Audit logs retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedAuditLogResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/notifications": {
      "get": {
        "operationId": "getNotifications",
        "summary": "Get user notifications",
        "description": "Get paginated list of notifications for the authenticated user with unread count. Scoped to the organization in the path: returns notifications belonging to that organization plus the user's account-level ones (those with no organizationId), which are shown in every organization.\n",
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size"
          },
          {
            "name": "unreadOnly",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "If true, only return unread notifications"
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/NotificationTypeEnum"
              }
            },
            "description": "Only return notifications of these types (comma-separated). Omit for all types. unreadCount is always the unfiltered total, so a filtered page never changes the badge.\n"
          }
        ],
        "responses": {
          "200": {
            "description": "Notifications retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedNotificationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/notifications/unread-count": {
      "get": {
        "operationId": "getUnreadNotificationCount",
        "summary": "Get unread notification count",
        "description": "Unread count alone, for the notification bell's badge. The list endpoint also returns this, but making the bell fetch a page of notifications just to render a number is the reason this exists.\n",
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Unread count retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnreadNotificationCountResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/notifications/{notificationId}": {
      "delete": {
        "operationId": "deleteNotification",
        "summary": "Delete a notification",
        "description": "Permanently delete one of the authenticated user's notifications. Also the escape hatch for a row the client cannot render.\n",
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "notificationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Notification ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Notification deleted",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/notifications/{notificationId}/read": {
      "patch": {
        "operationId": "markNotificationAsRead",
        "summary": "Mark notification as read",
        "description": "Mark a single notification as read.",
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "notificationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Notification ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Notification marked as read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/notifications/{notificationId}/unread": {
      "patch": {
        "operationId": "markNotificationAsUnread",
        "summary": "Mark notification as unread",
        "description": "Mark a single notification as unread.",
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "notificationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Notification ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Notification marked as unread",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/notifications/read-all": {
      "patch": {
        "operationId": "markAllNotificationsAsRead",
        "summary": "Mark all notifications as read",
        "description": "Mark all notifications for the authenticated user as read.",
        "tags": [
          "Notifications"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "204": {
            "description": "All notifications marked as read",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhooks",
        "description": "List all webhook subscriptions for the current organization. Requires webhook.view permission.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedWebhookResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Create webhook",
        "description": "Create a new webhook subscription for the current organization. Requires webhook.create permission.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/webhooks/event-types": {
      "get": {
        "operationId": "listWebhookEventTypes",
        "summary": "List available webhook event types",
        "description": "List all event types that can be subscribed to for webhook deliveries.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of available event types",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookEventTypeResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/webhooks/{webhookId}": {
      "get": {
        "operationId": "getWebhook",
        "summary": "Get webhook details",
        "description": "Get details of a specific webhook subscription. Requires webhook.view permission.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateWebhook",
        "summary": "Update webhook",
        "description": "Update an existing webhook subscription. Requires webhook.update permission.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete webhook",
        "description": "Delete a webhook subscription. Requires webhook.delete permission.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Webhook deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/webhooks/{webhookId}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "summary": "List webhook deliveries",
        "description": "List delivery attempts for a specific webhook. Requires webhook.view permission.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook ID"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          },
          {
            "name": "success",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter by success status"
          }
        ],
        "responses": {
          "200": {
            "description": "List of webhook deliveries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedWebhookDeliveryResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/webhooks/{webhookId}/test": {
      "post": {
        "operationId": "testWebhook",
        "summary": "Test a webhook",
        "description": "Sends a test \"Hello World\" payload to the webhook endpoint and returns the delivery result. Requires webhook.update permission.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "webhookId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Test delivery result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/integrations": {
      "get": {
        "operationId": "listIntegrations",
        "summary": "List organization integrations",
        "description": "List all integrations for the current organization. Requires integration.view permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "List of integrations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/IntegrationResponse"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/integrations/{provider}": {
      "get": {
        "operationId": "getIntegration",
        "summary": "Get integration by provider",
        "description": "Get integration details for a specific provider. Requires integration.view permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            },
            "description": "Integration provider (e.g., slack)"
          }
        ],
        "responses": {
          "200": {
            "description": "Integration details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "disconnectIntegration",
        "summary": "Disconnect integration",
        "description": "Disconnect an integration from the organization. Requires integration.delete permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            },
            "description": "Integration provider"
          }
        ],
        "responses": {
          "204": {
            "description": "Integration disconnected successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/integrations/slack/channels": {
      "get": {
        "operationId": "listSlackChannels",
        "summary": "List Slack channels",
        "description": "List available Slack channels for the connected workspace. Requires integration.view permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "List of Slack channels",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackChannelListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "No Slack integration found",
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/integrations/{provider}/subscriptions": {
      "get": {
        "operationId": "listIntegrationSubscriptions",
        "summary": "List all subscriptions for an integration",
        "description": "List all project subscriptions for an integration. Requires integration.view permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          },
          {
            "name": "projectId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by project ID"
          },
          {
            "name": "featureType",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/IntegrationFeatureTypeEnum"
            },
            "description": "Filter by feature type"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of subscriptions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedIntegrationSubscriptionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/integrations/{provider}/subscriptions": {
      "get": {
        "operationId": "listProjectIntegrationSubscriptions",
        "summary": "List subscriptions for a project",
        "description": "List integration subscriptions for a specific project. Requires integration.subscription.view permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of subscriptions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedIntegrationSubscriptionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createIntegrationSubscription",
        "summary": "Create integration subscription",
        "description": "Create a new integration subscription for a project. Requires integration.subscription.create permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateIntegrationSubscriptionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationSubscriptionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/integrations/{provider}/subscriptions/{subscriptionId}": {
      "get": {
        "operationId": "getIntegrationSubscription",
        "summary": "Get subscription details",
        "description": "Get details of a specific integration subscription. Requires integration.subscription.view permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          },
          {
            "name": "subscriptionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationSubscriptionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "updateIntegrationSubscription",
        "summary": "Update subscription",
        "description": "Update an integration subscription. Requires integration.subscription.update permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          },
          {
            "name": "subscriptionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateIntegrationSubscriptionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscription updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationSubscriptionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteIntegrationSubscription",
        "summary": "Delete subscription",
        "description": "Delete an integration subscription. Requires integration.subscription.delete permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          },
          {
            "name": "subscriptionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Subscription deleted",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/integrations/{provider}/subscriptions/{subscriptionId}/deliveries": {
      "get": {
        "operationId": "listSubscriptionDeliveries",
        "summary": "List subscription deliveries",
        "description": "List delivery history for a subscription. Requires integration.subscription.view permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          },
          {
            "name": "subscriptionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of deliveries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSlackDeliveryResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/integrations/{provider}/subscriptions/{subscriptionId}/test": {
      "post": {
        "operationId": "testIntegrationSubscription",
        "summary": "Test subscription",
        "description": "Send a test notification to verify the subscription is working. Requires integration.subscription.update permission.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/IntegrationProviderEnum"
            }
          },
          {
            "name": "subscriptionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Test delivery result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlackDeliveryResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "List custom events",
        "description": "List custom events for a project with pagination and filters. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "event",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by event name"
          },
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by channel"
          },
          {
            "name": "user_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by user ID"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "Page size"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort order by timestamp"
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of events",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedCustomEvent"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/{eventId}": {
      "get": {
        "operationId": "getEvent",
        "summary": "Get event details",
        "description": "Get details of a specific custom event. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Event ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Event details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomEvent"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/users": {
      "get": {
        "operationId": "listEventUsers",
        "summary": "List unique event users",
        "description": "List unique users who have triggered events, with pagination and filters. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Search by user ID (partial match)"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort order by last seen timestamp"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of event users",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedEventUsersResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/users/{userId}": {
      "get": {
        "operationId": "listEventsByUserId",
        "summary": "List events by user ID",
        "description": "List all custom events for a specific user ID within a project. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "User ID to filter events by"
          },
          {
            "name": "event",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by event name (partial match)"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "Page size"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort order by timestamp"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of events for the user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedCustomEvent"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/users/{userId}/details": {
      "get": {
        "operationId": "getEventUserDetails",
        "summary": "Get event user details",
        "description": "Get detailed information about a specific user including first/last seen and top events. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "User ID to get details for"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          }
        ],
        "responses": {
          "200": {
            "description": "User event details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventUserDetailsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/analytics/stats": {
      "get": {
        "operationId": "getEventsAnalyticsStats",
        "summary": "Get aggregated event statistics",
        "description": "Get aggregated event statistics including total events, unique users, and event breakdown. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "group_by",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "event",
                "user"
              ],
              "default": "event"
            },
            "description": "Group statistics by event name or user"
          },
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by channel"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          }
        ],
        "responses": {
          "200": {
            "description": "Event statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventStatsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/analytics/breakdown": {
      "get": {
        "operationId": "getEventsAnalyticsBreakdown",
        "summary": "Get events breakdown by dimension",
        "description": "Get events grouped by a specified dimension. Requires event.view permission.\n\nSupported dimensions:\n- event_name: Top events by name\n- user: Top users by event count\n- country, region, city: Geographic breakdown\n- browser, browser_version: Browser breakdown\n- os, os_version: Operating system breakdown\n- device, brand, model: Device breakdown\n- utm_source, utm_medium, utm_campaign: UTM parameters\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "dimension",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "event_name",
                "user",
                "country",
                "region",
                "city",
                "browser",
                "browser_version",
                "os",
                "os_version",
                "device",
                "brand",
                "model",
                "utm_source",
                "utm_medium",
                "utm_campaign"
              ]
            },
            "description": "Dimension to group events by"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Maximum number of results to return"
          }
        ],
        "responses": {
          "200": {
            "description": "Events breakdown by dimension",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedBreakdownResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/analytics/timeline": {
      "get": {
        "operationId": "getEventsAnalyticsTimeline",
        "summary": "Get events timeline",
        "description": "Get event counts over time with configurable interval. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "interval",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hour",
                "day",
                "week",
                "month"
              ],
              "default": "day"
            },
            "description": "Time interval for grouping data"
          },
          {
            "name": "event",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by specific event name"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          }
        ],
        "responses": {
          "200": {
            "description": "Events timeline data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventTimelineResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/analytics/aggregations": {
      "get": {
        "operationId": "getEventsAnalyticsAggregations",
        "summary": "Get aggregated unique events",
        "description": "Returns one aggregated row per unique event name within the selected time range\n(resolved from a `preset` or explicit `from`/`to`). Each row includes the total\nevent count, the number of unique users, and the first/last seen timestamps over\nthat range, plus a fixed 24-bucket hourly sparkline of the event's activity over\nthe last 24 hours (gaps filled with 0 so the frontend can render bars). Clicking a\nrow drills into the standard event listing filtered by that event name.\nRequires event.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by channel"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive substring filter on event name"
          },
          {
            "name": "user_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Case-insensitive substring filter on the resolved user (user_id / anonymous_id). Scopes every aggregation to events from matching users."
          },
          {
            "name": "preset",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            },
            "description": "Predefined date range preset. Takes precedence over from/to."
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Number of items per page"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort direction by event count"
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregated unique events",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedEventAggregations"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/bots": {
      "get": {
        "operationId": "listBots",
        "summary": "List bot/crawler requests",
        "description": "List bot/crawler request observations for a project with pagination, date-range preset, and optional actor-type filter. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Search by bot name, vendor, or path (partial match)"
          },
          {
            "name": "actorType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by actor type (verified_bot, spoofed_bot, suspected_bot)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-based)"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Items per page"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated bot/crawler requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedBotEventResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/bots/analytics/timeline": {
      "get": {
        "operationId": "getBotsAnalyticsTimeline",
        "summary": "Get bot/crawler timeline by vendor",
        "description": "Get bot/crawler request counts over time, grouped by vendor, with configurable\ngranularity. The date range is controlled via the preset parameter (or from/to when\npreset is omitted). Powers the per-vendor bar chart on the crawlers page.\nRequires event.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "interval",
            "in": "query",
            "required": false,
            "description": "Time-bucketing granularity for the timeline data. Defaults to day.",
            "schema": {
              "$ref": "#/components/schemas/TimelineInterval",
              "default": "day"
            }
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Bot/crawler counts over time grouped by vendor",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BotVendorTimelineResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/bots/analytics/countries": {
      "get": {
        "operationId": "getBotsAnalyticsCountries",
        "summary": "Get per-country bot/crawler breakdown",
        "description": "Get bot/crawler request counts and distinct bot counts grouped by country, paginated and\nordered by request count descending. The date range is controlled via the preset parameter\n(or from/to when preset is omitted). Powers the per-country panel on the crawlers page.\nRequires event.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Zero-based page number"
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 8
            },
            "description": "Items per page"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Per-country bot/crawler breakdown",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedBotCountryResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/bots/analytics/top": {
      "get": {
        "operationId": "getBotsAnalyticsTopBots",
        "summary": "Get top bots/crawlers by request count",
        "description": "Get the top bots/crawlers ranked by total request count (descending), capped to the\nrequested limit (default 10). The date range is controlled via the preset parameter\n(or from/to when preset is omitted). Powers the top-bots panel on the crawlers page.\nRequires event.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Maximum number of top bots to return"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Top bots/crawlers by request count",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopBotsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/bots/analytics/top-paths": {
      "get": {
        "operationId": "getBotsAnalyticsTopPaths",
        "summary": "Get top paths scraped by bots/crawlers",
        "description": "Get the top URL paths scraped by bots/crawlers ranked by total request count (descending),\ncapped to the requested limit (default 10). The date range is controlled via the preset\nparameter (or from/to when preset is omitted). Powers the top-scraped-paths panel.\nRequires event.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD). Used when preset is not provided."
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Maximum number of top paths to return"
          },
          {
            "name": "vendor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Restrict to one bot vendor/company (e.g. \"OpenAI\", \"Anthropic\", \"Google\", \"Perplexity\")"
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Top paths scraped by bots/crawlers by request count",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopPathsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/sessions": {
      "get": {
        "operationId": "listSessions",
        "summary": "List sessions",
        "description": "List aggregated sessions for a project with pagination. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Search by user ID or session ID (partial match)"
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of sessions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSessionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/sessions/{sessionId}": {
      "get": {
        "operationId": "getSessionDetail",
        "summary": "Get session detail",
        "description": "Get aggregated session detail by session ID. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Session identifier"
          }
        ],
        "responses": {
          "200": {
            "description": "Session detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionDetailResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/sessions/{sessionId}/events": {
      "get": {
        "operationId": "getSessionEvents",
        "summary": "List session events",
        "description": "List paginated events for a specific session. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Session identifier"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of session events",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedSessionEventResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/analytics/users": {
      "get": {
        "operationId": "listAnalyticsUsers",
        "summary": "List users from analytics",
        "description": "List aggregated user analytics for a project with pagination and filters. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/UserTypeFilterEnum"
            },
            "description": "Filter by user identification type"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Search by user_id or anonymous_id (partial match)"
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of user analytics summaries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedUserAnalyticsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/analytics/users/{userId}/summary": {
      "get": {
        "operationId": "getAnalyticsUserSummary",
        "summary": "Get user analytics summary",
        "description": "Get comprehensive analytics summary for a specific user. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Resolved user ID"
          }
        ],
        "responses": {
          "200": {
            "description": "User analytics summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsUserSummaryResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/analytics/users/{userId}/activity": {
      "get": {
        "operationId": "getAnalyticsUserActivity",
        "summary": "Get user activity heatmap",
        "description": "Get daily activity counts for a user over the last N months. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Resolved user ID"
          },
          {
            "name": "months",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 4
            },
            "description": "Number of months of activity to return"
          }
        ],
        "responses": {
          "200": {
            "description": "User activity heatmap data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsUserActivityResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/analytics/users/{userId}/events": {
      "get": {
        "operationId": "getAnalyticsUserEvents",
        "summary": "List user events",
        "description": "List paginated events for a specific user. Requires event.view permission.",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project key"
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Resolved user ID"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            },
            "description": "Page size"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of user events",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedAnalyticsUserEventResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/funnels": {
      "get": {
        "operationId": "listFunnels",
        "summary": "List saved funnels",
        "description": "List all saved funnel definitions for a project, filtered by environment. Requires event.view permission.",
        "tags": [
          "Funnels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional search term to filter funnels by name (case-insensitive)"
          }
        ],
        "responses": {
          "200": {
            "description": "List of saved funnels",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SavedFunnel"
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createFunnel",
        "summary": "Create a funnel",
        "description": "Create a new funnel definition for a project environment. Requires event.view permission.",
        "tags": [
          "Funnels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFunnelRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Funnel created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedFunnel"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. fewer than 2 steps)",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/funnels/{funnelId}": {
      "put": {
        "operationId": "updateFunnel",
        "summary": "Update a funnel",
        "description": "Update an existing funnel definition. Requires event.view permission.",
        "tags": [
          "Funnels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "funnelId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Funnel ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFunnelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Funnel updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedFunnel"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "deleteFunnel",
        "summary": "Delete a funnel",
        "description": "Delete a saved funnel definition. Requires event.view permission.",
        "tags": [
          "Funnels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "funnelId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Funnel ID"
          }
        ],
        "responses": {
          "204": {
            "description": "Funnel deleted",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/funnels/analyze": {
      "post": {
        "operationId": "analyzeFunnel",
        "summary": "Analyze a funnel",
        "description": "Run funnel analysis on event data. Builds a dynamic ClickHouse query with\nchained CTEs to track session/user progression through each step.\n\nIn session mode, all steps must occur within the same session.\nIn user mode, steps can span sessions but only identified users (with user_id) are included.\n\nRequires event.view permission.\n",
        "tags": [
          "Funnels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyzeFunnelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Funnel analysis results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelAnalysisResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. fewer than 2 steps)",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/funnels/steps/{stepNumber}/sessions": {
      "post": {
        "operationId": "getFunnelStepSessions",
        "summary": "Get sessions at a funnel step",
        "description": "Get sessions that reached or dropped off at a specific funnel step.\nReturns paginated session details with geo, device, and UTM data.\nRequires event.view permission.\n",
        "tags": [
          "Funnels"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "1-based step number in the funnel"
          },
          {
            "name": "mode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "reached",
                "dropped"
              ]
            },
            "description": "- reached: sessions/users that completed this step\n- dropped: sessions/users that completed this step but NOT the next\n"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            },
            "description": "Page number (0-indexed)"
          },
          {
            "name": "size",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 25
            },
            "description": "Page size"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyzeFunnelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Paginated session list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedFunnelSessionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/journeys/analyze": {
      "post": {
        "operationId": "analyzeJourney",
        "summary": "Analyze user journeys",
        "description": "Run journey analysis on screen_view event data. Computes page-to-page\nnavigation paths from session data using ClickHouse array functions.\nReturns the most common journey paths with session counts and percentages.\nRequires event.view permission.\n",
        "tags": [
          "Journeys"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project ID"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyzeJourneyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Journey analysis results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JourneyAnalysisResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. steps out of range)",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/web-analytics": {
      "get": {
        "operationId": "getProjectWebAnalytics",
        "summary": "Get project web analytics summary metrics",
        "description": "Get web analytics metrics for a specific project including unique visitors, sessions,\npageviews, bounce rate, average session duration, and revenue.\nReturns current period vs previous period with percentage change.\nRequires analytics.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date for the analytics period (inclusive, YYYY-MM-DD). Defaults to 7 days ago.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date for the analytics period (inclusive, YYYY-MM-DD). Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Web analytics metrics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebAnalyticsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/web-analytics/timeline": {
      "get": {
        "operationId": "getProjectWebAnalyticsTimeline",
        "summary": "Get project web analytics timeline data",
        "description": "Get time series data for pageviews, sessions, and unique visitors with flexible granularity\nfor a specific project.\nThe date range is controlled via from/to parameters and the granularity via the interval parameter.\nReturns current period and previous period data for comparison charts.\nRequires analytics.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date for the analytics period (inclusive, YYYY-MM-DD). Used when preset is not provided. Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date for the analytics period (inclusive, YYYY-MM-DD). Used when preset is not provided. Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "interval",
            "in": "query",
            "required": false,
            "description": "Time-bucketing granularity for the timeline data. Defaults to hour.",
            "schema": {
              "$ref": "#/components/schemas/TimelineInterval",
              "default": "hour"
            }
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Web analytics timeline data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlexibleWebTimelineResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/web-analytics/activity-heatmap": {
      "get": {
        "operationId": "getProjectWebAnalyticsActivityHeatmap",
        "summary": "Get visitor activity by hour of day",
        "description": "Get distinct visitors per (row, hour-of-day) cell — the \"when do people visit\" heatmap.\nRows are either the seven weekdays or the busiest countries, and hours are bucketed in\nthe project's reporting timezone (see the project settings endpoint).\n\nA heatmap needs at least a week of days to be readable, so a selected range narrower\nthan 7 days is widened to the last 7 days; wider ranges are used as selected. The\nwindow actually queried is echoed back in the response's from/to.\nRequires analytics.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "rowDimension",
            "in": "query",
            "required": false,
            "description": "What the rows are grouped by. Defaults to day_of_week.",
            "schema": {
              "$ref": "#/components/schemas/ActivityHeatmapRowDimension",
              "default": "day_of_week"
            }
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date for the analytics period (inclusive, YYYY-MM-DD). Defaults to 7 days ago.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date for the analytics period (inclusive, YYYY-MM-DD). Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          }
        ],
        "responses": {
          "200": {
            "description": "Visitor activity heatmap",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebAnalyticsActivityHeatmapResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/web-analytics/breakdown": {
      "get": {
        "operationId": "getProjectAnalyticsBreakdown",
        "summary": "Get project analytics breakdown by dimension",
        "description": "Get breakdown analytics for any supported dimension within a specific project.\n\nSupported dimensions:\n- Device: device, browser, browser_version, os, os_version, brand, model\n- Geo: country, region, city\n- UTM: utm_source, utm_medium, utm_campaign\n- Pages: path, entry_page, exit_page, top_page, referrer, top_referrer\n- Events: custom_events\n\nRequires analytics.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "dimension",
            "in": "query",
            "required": true,
            "description": "The dimension to get breakdown for",
            "schema": {
              "$ref": "#/components/schemas/BreakdownDimension"
            }
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date for the analytics period (inclusive, YYYY-MM-DD). Defaults to 7 days ago.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date for the analytics period (inclusive, YYYY-MM-DD). Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number (0-indexed, default 0)",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "description": "Number of results per page (default 10)",
            "schema": {
              "type": "integer",
              "default": 10,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Breakdown analytics data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedBreakdownResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/web-analytics/pages/duration": {
      "get": {
        "operationId": "getProjectPageDurationBreakdown",
        "summary": "Get project top pages by average time spent",
        "description": "Get the top 10 pages ranked by average time users spend on them for a specific project.\nUses ClickHouse window functions to calculate time between consecutive\nscreen_view events within the same session.\nGaps larger than 30 minutes are capped to prevent idle time inflation.\nRequires analytics.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date for the analytics period (inclusive, YYYY-MM-DD). Defaults to 7 days ago.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date for the analytics period (inclusive, YYYY-MM-DD). Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Top pages by average duration",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageDurationBreakdownResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/web-analytics/dimension/timeline": {
      "get": {
        "operationId": "getProjectDimensionTimeline",
        "summary": "Get project timeline data for a specific dimension value",
        "description": "Get timeline data for drilling down into a specific dimension value within a project.\nFor example, get daily counts for \"Chrome\" browser or \"US\" country.\nRequires analytics.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "dimension",
            "in": "query",
            "required": true,
            "description": "The dimension to get timeline for",
            "schema": {
              "$ref": "#/components/schemas/BreakdownDimension"
            }
          },
          {
            "name": "value",
            "in": "query",
            "required": true,
            "description": "The dimension value to filter by (e.g., \"Chrome\", \"US\")",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "description": "Predefined date range preset. When provided, overrides from/to parameters.",
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date for the analytics period (inclusive, YYYY-MM-DD). Defaults to 7 days ago.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date for the analytics period (inclusive, YYYY-MM-DD). Defaults to today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "filters",
            "in": "query",
            "required": false,
            "description": "Dimension filters in format dimension:operator:values.\nOperator is 'is' (include) or 'is_not' (exclude).\nValues are comma-separated. Can specify multiple filters.\nExample: filters=country:is:US,UK&filters=browser:is_not:Safari\n",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "style": "form",
            "explode": true
          },
          {
            "$ref": "#/components/parameters/ComparePreset"
          },
          {
            "$ref": "#/components/parameters/CompareFrom"
          },
          {
            "$ref": "#/components/parameters/CompareTo"
          }
        ],
        "responses": {
          "200": {
            "description": "Dimension timeline data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DimensionTimelineResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/web-analytics/paths": {
      "get": {
        "operationId": "getUniquePaths",
        "summary": "Get all unique page paths for a project",
        "description": "Returns all distinct path values from screen_view analytics events for the given project and environment.\nRequires analytics.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of unique paths",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UniqueValuesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/events/names": {
      "get": {
        "operationId": "getUniqueEventNames",
        "summary": "Get all unique event names for a project",
        "description": "Returns all distinct event_name values from custom events (excluding analytics channel)\nfor the given project and environment.\nRequires event.view permission.\n",
        "tags": [
          "Event Analytics"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "path",
            "required": true,
            "description": "Project ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of unique event names",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UniqueValuesResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/feature-flags/usage": {
      "get": {
        "operationId": "getFeatureFlagUsage",
        "summary": "Get feature flag usage statistics",
        "description": "Get usage statistics for feature flags in the current organization or a specific project.\nReturns evaluation counts, snapshot counts, and MAU (monthly active users) for the specified date range.\nUseful for billing and analytics dashboards.\n",
        "tags": [
          "Feature Flags"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional project key to filter usage by a specific project. If not provided, returns organization-wide usage."
          },
          {
            "name": "fromDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date for the usage period (inclusive, YYYY-MM-DD)"
          },
          {
            "name": "toDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date for the usage period (inclusive, YYYY-MM-DD)"
          }
        ],
        "responses": {
          "200": {
            "description": "Usage statistics retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagUsageResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/feature-flags/usage/timeline": {
      "get": {
        "operationId": "getFeatureFlagUsageTimeline",
        "summary": "Get feature flag usage timeline",
        "description": "Get daily feature flag usage statistics over time for charts and analytics.\nReturns evaluation and snapshot counts per day for the specified date range.\nUseful for visualizing usage trends.\n",
        "tags": [
          "Feature Flags"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "projectId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional project key to filter usage by a specific project. If not provided, returns organization-wide usage."
          },
          {
            "name": "fromDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date for the timeline period (inclusive, YYYY-MM-DD). Defaults to 30 days ago if not provided."
          },
          {
            "name": "toDate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date for the timeline period (inclusive, YYYY-MM-DD). Defaults to today if not provided."
          }
        ],
        "responses": {
          "200": {
            "description": "Timeline data retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagTimelineResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/plans": {
      "get": {
        "operationId": "getPublicBillingPlans",
        "summary": "List available billing plans",
        "description": "Get all public billing plans available for subscription.\nReturns plan details including features and pricing.\n",
        "tags": [
          "Billing"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "List of available billing plans",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingPlanListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/status": {
      "get": {
        "operationId": "getSubscriptionStatus",
        "summary": "Get subscription status",
        "description": "Get the lightweight subscription status for the current organization.\nReturns organization status, trial end date, and plan name.\nAvailable to all authenticated members of the organization (no special permission required).\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionStatusResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/subscription": {
      "get": {
        "operationId": "getCurrentSubscription",
        "summary": "Get current organization subscription",
        "description": "Get the current billing subscription for the authenticated user's organization.\nIncludes plan details, status, and any feature overrides.\n\n**Owner-only access**: Requires billing.subscription.view permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Current subscription details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingSubscriptionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/usage": {
      "get": {
        "operationId": "getCurrentUsage",
        "summary": "Get current usage statistics",
        "description": "Get usage statistics for the current billing period.\nReturns usage breakdown by feature with limits and percentages.\n\n**Owner-only access**: Requires billing.usage.view permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Current usage statistics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingUsageResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/entitlements/{featureCode}": {
      "get": {
        "operationId": "checkEntitlement",
        "summary": "Check feature entitlement",
        "description": "Check if the organization has access to a specific feature.\nReturns access status and any applicable limits.\n\n**Owner-only access**: Requires billing.entitlements.view permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "featureCode",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/BillingFeatureCodeEnum"
            },
            "description": "Feature code to check"
          }
        ],
        "responses": {
          "200": {
            "description": "Entitlement check result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEntitlementResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/features": {
      "get": {
        "operationId": "getAllFeatures",
        "summary": "Get all billing features",
        "description": "Get a list of all available billing features in the system.\nUseful for displaying feature comparison tables.\n",
        "tags": [
          "Billing"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "List of all billing features",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "features"
                  ],
                  "properties": {
                    "features": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BillingFeatureResponse"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/checkout": {
      "post": {
        "operationId": "createCheckoutSession",
        "summary": "Create Stripe checkout session",
        "description": "Create a Stripe Checkout session for upgrading to a paid plan.\nReturns a checkout URL that the frontend should redirect to.\n**Owner-only access**: Requires billing.subscription.manage permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCheckoutSessionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutSessionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/portal": {
      "post": {
        "operationId": "createBillingPortalSession",
        "summary": "Create Stripe billing portal session",
        "description": "Create a Stripe Billing Portal session for customer self-service.\nAllows customers to manage payment methods, view invoices, and cancel subscriptions.\n**Owner-only access**: Requires billing.subscription.manage permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBillingPortalRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Billing portal session created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingPortalResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/subscription/reactivate": {
      "post": {
        "operationId": "reactivateSubscription",
        "summary": "Reactivate cancelled subscription",
        "description": "Reactivate a subscription that was scheduled for cancellation at period end.\nThis will undo the cancellation and the subscription will continue normally.\n**Owner-only access**: Requires billing.subscription.manage permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription reactivated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionActionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/scheduled-change/cancel": {
      "post": {
        "operationId": "cancelScheduledChange",
        "summary": "Cancel a scheduled plan change",
        "description": "Cancel a scheduled (deferred) plan change — i.e. an upcoming downgrade that would\ntake effect at the end of the current billing period. Releases the Stripe schedule\nand clears the pending plan, so the organization stays on its current plan.\nReturns 400 if no plan change is scheduled.\n**Owner-only access**: Requires billing.subscription.manage permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Scheduled change cancelled successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CancelScheduledChangeResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/billing/transactions": {
      "get": {
        "operationId": "getBillingTransactions",
        "summary": "List billing transactions",
        "description": "Get billing transaction history (Stripe invoices) for the current organization.\nUses cursor-based pagination.\n\n**Owner-only access**: Requires billing.subscription.view permission.\n",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Number of transactions per page",
            "schema": {
              "type": "integer",
              "default": 20
            }
          },
          {
            "name": "startingAfter",
            "in": "query",
            "description": "Cursor for pagination (last invoice ID from previous page)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by invoice status",
            "schema": {
              "$ref": "#/components/schemas/BillingTransactionStatusEnum"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of billing transactions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingTransactionListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/feedback": {
      "post": {
        "operationId": "submitFeedback",
        "summary": "Submit feedback",
        "description": "Submit in-app feedback. Any authenticated organization member may submit. The submitter and their organization are derived from the authenticated session; only the message and page are provided by the client.",
        "tags": [
          "Feedback"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitFeedbackRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Feedback submitted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeedbackSubmissionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/feature-flags/snapshot": {
      "post": {
        "operationId": "getFeatureFlagSnapshot",
        "summary": "Get evaluated feature flags snapshot",
        "description": "Evaluate all feature flags for the project and environment associated with the SDK key.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeatureFlagSnapshotRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feature flags evaluated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlagSnapshotResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/feature-flags/evaluate": {
      "post": {
        "operationId": "evaluateFeatureFlag",
        "summary": "Evaluate a single feature flag (OpenFeature compatible)",
        "description": "Evaluate a single feature flag for the project and environment associated with the SDK key.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvaluateFlagRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feature flag evaluated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluatedFeatureFlagResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/feature-flags/config": {
      "get": {
        "operationId": "getFeatureFlagConfiguration",
        "summary": "Get feature flag configuration for client-side evaluation",
        "description": "Returns the complete feature flag configuration for client-side local evaluation. Supports ETag-based caching.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ETag from previous response for cache validation"
          }
        ],
        "responses": {
          "200": {
            "description": "Feature flag configuration retrieved successfully",
            "headers": {
              "ETag": {
                "description": "ETag for cache validation",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "Cache control directives",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlagConfigurationResponse"
                }
              }
            }
          },
          "304": {
            "description": "Configuration not modified (ETag matched)"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/logs": {
      "post": {
        "operationId": "logEvent",
        "summary": "Log a custom event",
        "description": "Log a custom event from SDK. The project is automatically determined from the API key.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LogEventRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Event accepted for async processing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LogEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/logs/batch": {
      "post": {
        "operationId": "logEventBatch",
        "summary": "Log a batch of events",
        "description": "Log a batch of events from SDK. Supports offline-queued events with client-side session reconstruction.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchLogEventRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch accepted for async processing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchLogEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/ingest/v1/server": {
      "post": {
        "operationId": "ingestServerRequests",
        "summary": "Ingest server-observed requests for crawler/bot attribution",
        "description": "Ingest requests observed by the customer's server/edge middleware so crawlers that never run the JS SDK (GPTBot, Googlebot, etc.) can be detected and attributed server-side. The backend classifies each request's actor; bot/crawler requests are stored (when bot detection is on) flagged with attribution, while human requests are ignored to avoid double-counting the SDK. Part of the ingestion family at /ingest/v1/{source}; authenticated with the SDK/API key, which resolves the project. Future per-vendor drains (Vercel, CloudFront, Netlify, Fastly) slot in under the same namespace.",
        "tags": [
          "Ingestion"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServerEventBatchRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Batch accepted for async processing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchLogEventResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/identify": {
      "post": {
        "operationId": "identifyUser",
        "summary": "Link anonymous user to identified user",
        "description": "Link the server-derived anonymous_id to a user_id for identity resolution. Call this when a user signs up or logs in.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IdentifyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Identity linked successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentifyResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/in-app-messages": {
      "get": {
        "operationId": "getActiveInAppMessages",
        "summary": "Get active in-app messages",
        "description": "Get active in-app messages for the current environment.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "SDK end-user ID (to filter show_once messages)"
          },
          {
            "name": "metadata",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "JSON-encoded key-value map for targeting evaluation"
          }
        ],
        "responses": {
          "200": {
            "description": "Active messages retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SdkActiveMessagesResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/sdk/v1/in-app-messages/views": {
      "post": {
        "operationId": "recordInAppMessageView",
        "summary": "Record a message view",
        "description": "Record that a user has viewed an in-app message.",
        "tags": [
          "SDK"
        ],
        "security": [
          {
            "SdkKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordMessageViewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "View recorded successfully"
          },
          "400": {
            "$ref": "#/components/responses/BadRequestError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/v1/auth/key-info": {
      "get": {
        "operationId": "getKeyInfo",
        "summary": "Get API key context information",
        "description": "Returns the project, organization, and org slug associated with the private API key.",
        "tags": [
          "CLI"
        ],
        "parameters": [
          {
            "name": "X-API-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Private API key for authentication"
          }
        ],
        "responses": {
          "200": {
            "description": "Key info retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeyInfoResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/trackable-actions": {
      "get": {
        "operationId": "listTrackableActions",
        "summary": "List trackable actions",
        "description": "The project's action log, newest first. Also reachable from agents, but through the MCP tools the Spring app serves directly (TrackableActionMcpTools) rather than through this spec — MCP is not a derived-spec audience.",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "verb",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/TrackableActionVerbEnum"
            }
          },
          {
            "name": "platform",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text match against the description.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "recommendationId",
            "in": "query",
            "required": false,
            "description": "Only the action produced by this content recommendation, if any.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Only actions that started on or after this date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Only actions that started on or before this date.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Actions retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackableActionListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "createTrackableAction",
        "summary": "Log a trackable action",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTrackableActionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Action logged successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackableActionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Log a trackable action"
      }
    },
    "/{orgSlug}/projects/{projectId}/trackable-actions/{actionId}": {
      "get": {
        "operationId": "getTrackableAction",
        "summary": "Get one trackable action",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "actionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Action retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackableActionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Get one trackable action"
      },
      "patch": {
        "operationId": "updateTrackableAction",
        "summary": "Update a trackable action",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "actionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTrackableActionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Action updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackableActionResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Update a trackable action"
      },
      "delete": {
        "operationId": "deleteTrackableAction",
        "summary": "Delete a trackable action",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "actionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Action deleted successfully",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        },
        "description": "Delete a trackable action"
      }
    },
    "/{orgSlug}/projects/{projectId}/trackable-actions/{actionId}/impact": {
      "get": {
        "operationId": "getTrackableActionImpact",
        "summary": "What one action moved",
        "description": "The published → crawled → cited → referred chain for a single action, with equal windows either side of its start date.\n\nDeliberately no brand mention rate: at one sample per prompt per engine per day it cannot carry a single action's signal, so this reports counts of things that happened rather than a rate that would look like an answer without being one. Overlapping actions and open campaign windows come back as confounders rather than being corrected for.",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "actionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "windowDays",
            "in": "query",
            "required": false,
            "description": "Days on each side of the start date. Defaults to 21, max 90.",
            "schema": {
              "type": "integer",
              "default": 21
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Impact retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackableActionImpactResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/trackable-actions/candidates": {
      "get": {
        "operationId": "listTrackableActionCandidates",
        "summary": "Pages the crawl noticed that nobody logged",
        "description": "Detected but unconfirmed actions, newest first. Confirm one with PATCH `confirmed: true`, refuse it with PATCH `dismissed: true`.",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Candidates retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackableActionCandidateListResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/{orgSlug}/projects/{projectId}/trackable-actions/system-events": {
      "get": {
        "operationId": "listTrackableActionSystemEvents",
        "summary": "Things in this window that nobody's customer did",
        "description": "Engine model-version changes inside the window, for drawing beside a project's own logged actions. Derived from `ai_visibility_runs.model_version`, so it needs no external data and cannot go stale.",
        "tags": [
          "Trackable Actions"
        ],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrgSlugPath"
          },
          {
            "$ref": "#/components/parameters/projectIdPathParam"
          },
          {
            "name": "preset",
            "in": "query",
            "required": false,
            "schema": {
              "$ref": "#/components/schemas/DateRangePreset"
            },
            "description": "Predefined date range preset, resolved in the project's reporting timezone. Takes precedence over from/to."
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Start date filter (inclusive, YYYY-MM-DD). Used when preset is not provided; send with `to`."
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "End date filter (inclusive, YYYY-MM-DD). Used when preset is not provided; send with `from`."
          }
        ],
        "responses": {
          "200": {
            "description": "System events retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrackableActionSystemEventsResponse"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": [
          "MCP"
        ],
        "operationId": "mcpStreamableHttp",
        "summary": "Kitbase MCP server (Streamable HTTP, JSON-RPC 2.0)",
        "description": "The Model Context Protocol endpoint. Speak JSON-RPC 2.0 over Streamable HTTP: `initialize`, then `tools/list` and `tools/call`. A response is either a single JSON object or an SSE stream, depending on the `Accept` header the client sends.\n\nAuthorize with OAuth 2.1 + PKCE (an unauthenticated request answers `401` with a `WWW-Authenticate: Bearer resource_metadata=\"...\"` header that starts the discovery chain), or, for a headless client, with a private API key in `Authorization: Bearer sk_kitbase_...`.\n\nMachine-readable description of this server: `https://api.kitbase.dev/mcp/server-card`. Human documentation: https://docs.kitbase.dev/sdks/mcp",
        "security": [
          {
            "McpOAuth": [
              "mcp:read"
            ]
          },
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "A JSON-RPC 2.0 request object.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "JSON-RPC 2.0 request (`jsonrpc`, `id`, `method`, `params`)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response. `application/json` for a single result, `text/event-stream` when the server streams.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequestsError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/mcp/server-card": {
      "get": {
        "tags": [
          "MCP"
        ],
        "operationId": "getMcpServerCard",
        "summary": "MCP server card",
        "description": "The Model Context Protocol server card for the Kitbase MCP server: its name, version, icons, the Streamable HTTP remote to connect to, the protocol versions it negotiates, and how to authorize. Anonymous, cacheable, and served with a strong ETag. Also listed in the catalog at https://kitbase.dev/.well-known/ai-catalog.json.",
        "security": [],
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "ETag from a previous response. Answered with `304` when it still matches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The server card.",
            "headers": {
              "ETag": {
                "description": "Strong ETag — the hex SHA-256 of the body.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`public, max-age=3600`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/mcp-server-card+json": {
                "schema": {
                  "type": "object",
                  "description": "https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json"
                }
              }
            }
          },
          "304": {
            "description": "Not modified — the supplied `If-None-Match` still matches."
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "operationId": "getOpenApiJson",
        "summary": "This document, as JSON",
        "description": "The public OpenAPI 3.0.0 description of this API (version 1.0.0), as JSON. Anonymous, cacheable, and served with a strong ETag. This is the canonical machine-readable contract — generate a client from it rather than hand-writing requests.",
        "security": [],
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "ETag from a previous response. Answered with `304` when it still matches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The OpenAPI document.",
            "headers": {
              "ETag": {
                "description": "Strong ETag — the hex SHA-256 of the body.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`public, max-age=3600`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "304": {
            "description": "Not modified — the supplied `If-None-Match` still matches."
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/openapi.yaml": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "operationId": "getOpenApiYaml",
        "summary": "This document, as YAML",
        "description": "The same document as `/openapi.json`, serialized as YAML (media type `application/yaml`, RFC 9512).",
        "security": [],
        "parameters": [
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "description": "ETag from a previous response. Answered with `304` when it still matches.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The OpenAPI document.",
            "headers": {
              "ETag": {
                "description": "Strong ETag — the hex SHA-256 of the body.",
                "schema": {
                  "type": "string"
                }
              },
              "Cache-Control": {
                "description": "`public, max-age=3600`.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "304": {
            "description": "Not modified — the supplied `If-None-Match` still matches."
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "UserStatusEnum": {
        "type": "string",
        "enum": [
          "active",
          "inactive",
          "pending",
          "suspended"
        ],
        "description": "User account status"
      },
      "SidebarNavMode": {
        "type": "string",
        "enum": [
          "drill",
          "categorized"
        ],
        "description": "Sidebar navigation layout preference"
      },
      "InvitationStatusEnum": {
        "type": "string",
        "enum": [
          "pending",
          "accepted",
          "expired",
          "canceled"
        ],
        "description": "Invitation status"
      },
      "NotificationTypeEnum": {
        "type": "string",
        "enum": [
          "invitation_received",
          "build_completed",
          "member_joined",
          "member_removed",
          "log_rate_exceeded",
          "usage_limit_warning",
          "role_updated",
          "data_retention_cleanup",
          "data_retention_warning",
          "admin_broadcast",
          "backlink_detected",
          "payment_failed",
          "export_completed",
          "workflow_report",
          "workflow_approval_requested",
          "marketplace_order_paid",
          "marketplace_order_published",
          "marketplace_order_revision_requested",
          "marketplace_order_rejected",
          "marketplace_order_link_lost",
          "marketplace_order_refunded"
        ],
        "description": "Type of notification. MUST contain every type a NotificationHandler creates — NotificationService maps stored rows through NotificationTypeEnum.fromValue, which throws (VAL_001) on any value missing here, breaking GET /notifications for that user.\nHandlers are not the only writers: workflow node executors call NotificationService directly too (workflow_report, workflow_approval_requested). ApprovalGateExecutor references this generated constant rather than a literal, which is what a listing omission should look like everywhere — a compile error, not a broken inbox.\nThe marketplace_order_* values are the worked example of that failure: AbstractMarketplaceOrderNotificationHandler has been writing them as IN_APP rows while they were absent here, so the list endpoint 500'd permanently for every member of an org that had ever placed an order, with no way to clear the unreadable row.\n"
      },
      "WebhookEventTypeEnum": {
        "type": "string",
        "enum": [
          "invitation_received",
          "build_completed",
          "member_joined",
          "member_removed",
          "log_rate_exceeded",
          "usage_limit_warning",
          "role_updated",
          "data_retention_cleanup",
          "data_retention_warning",
          "organization_created",
          "organization_updated",
          "invitation_accepted",
          "invitation_canceled",
          "invitation_revoked",
          "project_created",
          "project_updated",
          "project_deleted",
          "environment_created",
          "environment_updated",
          "environment_deleted",
          "feature_flag_created",
          "feature_flag_updated",
          "feature_flag_deleted",
          "segment_created",
          "segment_updated",
          "segment_deleted",
          "sdk_key_created",
          "sdk_key_deleted",
          "api_key_created",
          "api_key_deleted",
          "ota_update_deployed",
          "webhook_created",
          "webhook_updated",
          "webhook_deleted",
          "payment_failed",
          "custom_event_created",
          "backlink_detected"
        ],
        "description": "Event types that can trigger webhook deliveries"
      },
      "ProjectType": {
        "type": "string",
        "enum": [
          "react",
          "nextjs",
          "vue",
          "angular",
          "svelte",
          "nuxt",
          "nodejs",
          "python",
          "go",
          "java",
          "rust",
          "dotnet",
          "others"
        ],
        "description": "The framework or technology type of the project"
      },
      "BreakdownDimension": {
        "type": "string",
        "enum": [
          "device",
          "browser",
          "browser_version",
          "os",
          "os_version",
          "brand",
          "model",
          "country",
          "region",
          "city",
          "utm_source",
          "utm_medium",
          "utm_campaign",
          "path",
          "entry_page",
          "exit_page",
          "top_page",
          "referrer",
          "top_referrer",
          "outbound_link",
          "custom_events"
        ],
        "description": "Dimension for analytics breakdown queries:\n- Device: device, browser, browser_version, os, os_version, brand, model\n- Geo: country, region, city\n- UTM: utm_source, utm_medium, utm_campaign\n- Pages: path, entry_page, exit_page, top_page, referrer, top_referrer, outbound_link\n- Events: custom_events\n"
      },
      "UserTypeFilterEnum": {
        "type": "string",
        "enum": [
          "all",
          "identified",
          "anonymous"
        ],
        "description": "Filter users by identification status:\n- all: Return all users (default)\n- identified: Only users with a known user_id\n- anonymous: Only anonymous users (no user_id)\n"
      },
      "TargetingCondition": {
        "type": "object",
        "description": "A single targeting condition",
        "required": [
          "field",
          "op",
          "value"
        ],
        "properties": {
          "field": {
            "type": "string",
            "description": "Metadata field name (e.g., user_id, device_id)"
          },
          "op": {
            "type": "string",
            "enum": [
              "eq",
              "neq"
            ],
            "description": "Operator - eq (equals), neq (not equals)"
          },
          "value": {
            "type": "string",
            "description": "Value to compare against"
          }
        }
      },
      "TargetingConditions": {
        "type": "object",
        "description": "Targeting conditions with AND/OR operator",
        "required": [
          "operator",
          "conditions"
        ],
        "properties": {
          "operator": {
            "type": "string",
            "enum": [
              "and",
              "or"
            ],
            "description": "How conditions are combined"
          },
          "conditions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TargetingCondition"
            },
            "description": "List of targeting conditions"
          }
        }
      },
      "CreateWebhookRequest": {
        "type": "object",
        "description": "Request to create a new webhook subscription",
        "required": [
          "name",
          "url",
          "events"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Human-readable name for the webhook"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "The URL to send webhook payloads to"
          },
          "secret": {
            "type": "string",
            "maxLength": 255,
            "description": "Optional secret for HMAC signature verification"
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/WebhookEventTypeEnum"
            },
            "description": "List of events this webhook should receive"
          },
          "enabled": {
            "type": "boolean",
            "default": true,
            "description": "Whether the webhook is enabled"
          }
        }
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "description": "Request to update an existing webhook subscription",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Human-readable name for the webhook"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "description": "The URL to send webhook payloads to"
          },
          "secret": {
            "type": "string",
            "maxLength": 255,
            "description": "Secret for HMAC signature verification (send empty string to clear)"
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/WebhookEventTypeEnum"
            },
            "description": "List of events this webhook should receive"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the webhook is enabled"
          }
        }
      },
      "WebhookResponse": {
        "type": "object",
        "description": "Webhook subscription details",
        "required": [
          "id",
          "name",
          "url",
          "events",
          "enabled",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the webhook"
          },
          "name": {
            "type": "string",
            "description": "Human-readable name for the webhook"
          },
          "url": {
            "type": "string",
            "description": "The URL webhook payloads are sent to"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventTypeEnum"
            },
            "description": "List of events this webhook receives"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the webhook is enabled"
          },
          "lastSuccessAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of last successful delivery"
          },
          "lastFailureAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of last failed delivery"
          },
          "failureCount": {
            "type": "integer",
            "description": "Number of consecutive failures"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the webhook was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the webhook was last updated"
          }
        }
      },
      "WebhookDeliveryResponse": {
        "type": "object",
        "description": "Webhook delivery record",
        "required": [
          "id",
          "webhookId",
          "eventType",
          "success",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the delivery"
          },
          "webhookId": {
            "type": "string",
            "description": "ID of the webhook subscription"
          },
          "eventType": {
            "type": "string",
            "description": "Type of event that triggered the delivery"
          },
          "statusCode": {
            "type": "integer",
            "description": "HTTP status code of the response"
          },
          "success": {
            "type": "boolean",
            "description": "Whether the delivery was successful"
          },
          "requestPayload": {
            "type": "object",
            "additionalProperties": true,
            "description": "The payload that was sent"
          },
          "responseBody": {
            "type": "string",
            "description": "Response body from the webhook endpoint (truncated)"
          },
          "durationMs": {
            "type": "integer",
            "description": "Duration of the request in milliseconds"
          },
          "errorMessage": {
            "type": "string",
            "description": "Error message if the delivery failed"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the delivery was attempted"
          }
        }
      },
      "PaginatedWebhookResponse": {
        "type": "object",
        "description": "Paginated list of webhooks",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "PaginatedWebhookDeliveryResponse": {
        "type": "object",
        "description": "Paginated list of webhook deliveries",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDeliveryResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "WebhookEventTypeResponse": {
        "type": "object",
        "description": "Available webhook event type",
        "required": [
          "code",
          "label",
          "description",
          "category"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Event type code"
          },
          "label": {
            "type": "string",
            "description": "Human-readable label"
          },
          "description": {
            "type": "string",
            "description": "Description of when this event fires"
          },
          "category": {
            "type": "string",
            "description": "Category grouping for the event type"
          }
        }
      },
      "RefreshTokenRequest": {
        "type": "object",
        "description": "Request to refresh access token",
        "required": [
          "refreshToken"
        ],
        "properties": {
          "refreshToken": {
            "type": "string",
            "description": "Refresh token"
          }
        }
      },
      "CreateOrganizationRequest": {
        "type": "object",
        "description": "Request to create a new organization",
        "required": [
          "name",
          "orgSlug"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Organization name"
          },
          "orgSlug": {
            "type": "string",
            "description": "Organization slug (unique identifier used in URLs)"
          },
          "description": {
            "type": "string",
            "description": "Organization description"
          },
          "logoUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL to the organization logo image"
          }
        }
      },
      "UpdateOrganizationRequest": {
        "type": "object",
        "description": "Request to update an organization",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Organization name"
          },
          "logoUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL to the organization logo image"
          },
          "require2fa": {
            "type": "boolean",
            "description": "Whether this organization requires members to have 2FA enabled"
          },
          "dataRetentionNotificationsEnabled": {
            "type": "boolean",
            "description": "Whether this organization receives data retention emails and in-app notifications"
          }
        }
      },
      "CreateInvitationRequest": {
        "type": "object",
        "description": "Request to create an invitation",
        "required": [
          "email",
          "role"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email of the invited user"
          },
          "role": {
            "type": "string",
            "description": "Role Id"
          }
        }
      },
      "UpdateInvitationRequest": {
        "type": "object",
        "description": "Request to update an invitation",
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "type": "string",
            "description": "New role id"
          }
        }
      },
      "UpdateMemberRoleRequest": {
        "type": "object",
        "description": "Request to update a member's role",
        "required": [
          "roleId"
        ],
        "properties": {
          "roleId": {
            "type": "string",
            "description": "New role ID"
          }
        }
      },
      "CreateProjectRequest": {
        "type": "object",
        "description": "Request to create a new project",
        "required": [
          "name",
          "projectType"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Project name"
          },
          "description": {
            "type": "string",
            "description": "Project description"
          },
          "projectType": {
            "$ref": "#/components/schemas/ProjectType"
          },
          "websiteDomain": {
            "type": "string",
            "nullable": true,
            "description": "Optional public website domain for the project (registrable eTLD+1). Normalized on write (scheme/www/path stripped); invalid input is rejected with 400. Omit or leave empty for projects with no public website (apps, dashboards)."
          },
          "keywordLocationCode": {
            "type": "integer",
            "nullable": true,
            "description": "Default keyword research market (a DataForSEO location code from GET /{orgSlug}/keyword-markets). Omit to leave the project on 2840 (United States). An unsupported code is rejected with 400."
          },
          "keywordLanguageCode": {
            "type": "string",
            "nullable": true,
            "description": "Language paired with keywordLocationCode. Omit to use that market's default language. A language DataForSEO does not serve in that country is rejected with 400 — the provider bills such a task before failing it."
          }
        }
      },
      "UpdateProjectRequest": {
        "type": "object",
        "description": "Request to update a project",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Project name"
          },
          "description": {
            "type": "string",
            "description": "Project description"
          },
          "websiteDomain": {
            "type": "string",
            "nullable": true,
            "description": "The project's public website domain (registrable eTLD+1). Send a non-empty value to set it (normalized on write; invalid input rejected with 400), an empty string to clear it, or omit the field entirely to leave the current value unchanged."
          },
          "keywordLocationCode": {
            "type": "integer",
            "nullable": true,
            "description": "Default keyword research market (a DataForSEO location code). Omit to leave it unchanged; an unsupported code is rejected with 400."
          },
          "keywordLanguageCode": {
            "type": "string",
            "nullable": true,
            "description": "Language paired with keywordLocationCode. Omit to leave it unchanged; sending a location without a language resolves to that market's default."
          }
        }
      },
      "UserResponse": {
        "type": "object",
        "description": "User information",
        "required": [
          "id",
          "email",
          "firstName",
          "lastName",
          "status",
          "organizations",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "User ID"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "User's email address"
          },
          "firstName": {
            "type": "string",
            "description": "User's first name"
          },
          "lastName": {
            "type": "string",
            "description": "User's last name"
          },
          "status": {
            "$ref": "#/components/schemas/UserStatusResponse"
          },
          "organizations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserOrganizationMembership"
            },
            "description": "List of organizations the user is a member of"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the user was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the user was last updated"
          }
        }
      },
      "CurrentUserResponse": {
        "type": "object",
        "description": "Current user information with role and permissions for the current organization (determined by orgSlug path parameter)",
        "required": [
          "id",
          "email",
          "firstName",
          "lastName",
          "status",
          "organizations",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "User ID"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "User's email address"
          },
          "firstName": {
            "type": "string",
            "description": "User's first name"
          },
          "lastName": {
            "type": "string",
            "description": "User's last name"
          },
          "status": {
            "$ref": "#/components/schemas/UserStatusResponse"
          },
          "organizations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserOrganizationMembership"
            },
            "description": "List of organizations the user is a member of"
          },
          "currentOrganizationRole": {
            "$ref": "#/components/schemas/RoleWithPermissionsResponse",
            "description": "The user's role with permissions in the current organization (determined by orgSlug path parameter). Null if not in an organization context.",
            "nullable": true
          },
          "twoFactorEnabled": {
            "type": "boolean",
            "description": "Whether two-factor authentication is enabled for this user",
            "default": false
          },
          "selfHosted": {
            "type": "boolean",
            "description": "Whether this instance is self-hosted (unlimited usage, no billing)",
            "default": false
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the user was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the user was last updated"
          },
          "sidebarNavMode": {
            "$ref": "#/components/schemas/SidebarNavMode",
            "nullable": true,
            "description": "User's sidebar navigation layout preference (null = client default)"
          }
        }
      },
      "UpdateUserRequest": {
        "type": "object",
        "description": "Request to update user profile",
        "properties": {
          "firstName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "User's first name"
          },
          "lastName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "User's last name"
          }
        }
      },
      "UserOrganizationMembership": {
        "type": "object",
        "description": "User's membership in an organization",
        "required": [
          "organization",
          "role"
        ],
        "properties": {
          "organization": {
            "$ref": "#/components/schemas/UserOrganizationResponse"
          },
          "role": {
            "$ref": "#/components/schemas/RoleResponse"
          },
          "invitationStatus": {
            "$ref": "#/components/schemas/InvitationStatusResponse",
            "nullable": true,
            "description": "Invitation status (null for organization owners who were not invited)"
          }
        }
      },
      "UserOrganizationResponse": {
        "type": "object",
        "description": "Minimal organization information for user response",
        "required": [
          "id",
          "name",
          "orgSlug"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Organization ID"
          },
          "name": {
            "type": "string",
            "description": "Organization name"
          },
          "orgSlug": {
            "type": "string",
            "description": "Organization slug"
          }
        }
      },
      "UserStatusResponse": {
        "type": "object",
        "description": "User status information",
        "required": [
          "id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Status ID"
          },
          "status": {
            "$ref": "#/components/schemas/UserStatusEnum"
          }
        }
      },
      "AuthResponse": {
        "type": "object",
        "description": "Authentication response. If twoFactorRequired is true, accessToken and refreshToken will be null and tempToken will be provided for 2FA verification. If twoFactorSetupRequired is true, the user must set up 2FA before accessing organizations that require it.",
        "properties": {
          "accessToken": {
            "type": "string",
            "description": "JWT access token (null if 2FA required or setup required)",
            "nullable": true
          },
          "refreshToken": {
            "type": "string",
            "description": "Refresh token (null if 2FA required or setup required)",
            "nullable": true
          },
          "user": {
            "$ref": "#/components/schemas/UserResponse"
          },
          "twoFactorRequired": {
            "type": "boolean",
            "description": "Whether two-factor authentication verification is required to complete login (user has 2FA enabled)",
            "default": false
          },
          "twoFactorSetupRequired": {
            "type": "boolean",
            "description": "Whether two-factor authentication setup is required (user belongs to an org that requires 2FA but hasn't set it up)",
            "default": false
          },
          "tempToken": {
            "type": "string",
            "description": "Temporary token for 2FA verification or setup (only present if twoFactorRequired or twoFactorSetupRequired is true)",
            "nullable": true
          },
          "twoFactorMethods": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "totp",
                "backup"
              ]
            },
            "description": "Available 2FA methods for this user (only present if twoFactorRequired is true)",
            "nullable": true
          }
        }
      },
      "TwoFactorSetupResponse": {
        "type": "object",
        "description": "Response when initiating 2FA setup",
        "required": [
          "secret",
          "qrCodeUri",
          "backupCodes"
        ],
        "properties": {
          "secret": {
            "type": "string",
            "description": "The TOTP secret key (base32 encoded)"
          },
          "qrCodeUri": {
            "type": "string",
            "description": "The otpauth:// URI for QR code generation"
          },
          "backupCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "One-time use backup codes for account recovery"
          }
        }
      },
      "TwoFactorEnableRequest": {
        "type": "object",
        "description": "Request to enable 2FA after setup",
        "required": [
          "code"
        ],
        "properties": {
          "code": {
            "type": "string",
            "minLength": 6,
            "maxLength": 6,
            "pattern": "^\\d{6}$",
            "description": "The 6-digit TOTP code from authenticator app"
          }
        }
      },
      "TwoFactorDisableRequest": {
        "type": "object",
        "description": "Request to disable 2FA",
        "required": [
          "password",
          "code"
        ],
        "properties": {
          "password": {
            "type": "string",
            "description": "Current account password for verification"
          },
          "code": {
            "type": "string",
            "minLength": 6,
            "maxLength": 10,
            "description": "Current TOTP code or backup code"
          }
        }
      },
      "TwoFactorStatusResponse": {
        "type": "object",
        "description": "Response indicating 2FA status",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether 2FA is currently enabled"
          },
          "backupCodesRemaining": {
            "type": "integer",
            "description": "Number of unused backup codes remaining",
            "nullable": true
          }
        }
      },
      "BackupCodesResponse": {
        "type": "object",
        "description": "Response containing newly generated backup codes",
        "required": [
          "backupCodes"
        ],
        "properties": {
          "backupCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "New one-time use backup codes (previous codes are invalidated)"
          }
        }
      },
      "TwoFactorRequiredOrganization": {
        "type": "object",
        "description": "Organization that requires 2FA to be enabled",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Organization ID"
          },
          "name": {
            "type": "string",
            "description": "Organization name"
          }
        }
      },
      "TwoFactorDisableForbiddenResponse": {
        "type": "object",
        "description": "Response when 2FA cannot be disabled due to organization requirements",
        "required": [
          "error",
          "organizations"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Error code",
                "example": "2FA_001"
              },
              "message": {
                "type": "string",
                "description": "Error message",
                "example": "Cannot disable 2FA because one or more organizations require it"
              }
            }
          },
          "organizations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TwoFactorRequiredOrganization"
            },
            "description": "List of organizations that require 2FA"
          }
        }
      },
      "PasskeyResponse": {
        "type": "object",
        "description": "A registered passkey",
        "required": [
          "id",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Passkey id"
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "User-friendly label"
          },
          "transports": {
            "type": "string",
            "nullable": true,
            "description": "Comma-separated transport hints (usb,nfc,ble,internal,hybrid)"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the passkey was added"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the passkey was last used to sign in"
          }
        }
      },
      "PasskeyListResponse": {
        "type": "object",
        "description": "The current user's registered passkeys",
        "required": [
          "passkeys"
        ],
        "properties": {
          "passkeys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PasskeyResponse"
            }
          }
        }
      },
      "PasskeyRenameRequest": {
        "type": "object",
        "description": "Rename a passkey",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "New user-friendly label"
          }
        }
      },
      "OrganizationResponse": {
        "type": "object",
        "description": "Organization information",
        "required": [
          "id",
          "name",
          "orgSlug",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Organization ID"
          },
          "name": {
            "type": "string",
            "description": "Organization name"
          },
          "orgSlug": {
            "type": "string",
            "description": "Organization slug (unique identifier used in URLs)"
          },
          "description": {
            "type": "string",
            "description": "Organization description"
          },
          "logoUrl": {
            "type": "string",
            "description": "URL to the organization logo image"
          },
          "require2fa": {
            "type": "boolean",
            "description": "Whether this organization requires members to have 2FA enabled",
            "default": false
          },
          "dataRetentionNotificationsEnabled": {
            "type": "boolean",
            "description": "Whether this organization receives data retention emails and in-app notifications",
            "default": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the organization was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the organization was last updated"
          }
        }
      },
      "RoleResponse": {
        "type": "object",
        "description": "Role information (roles are now global across all organizations)",
        "required": [
          "id",
          "name",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Role ID"
          },
          "name": {
            "type": "string",
            "description": "Role name"
          },
          "description": {
            "type": "string",
            "description": "Role description"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the role was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the role was last updated"
          }
        }
      },
      "PermissionCode": {
        "type": "string",
        "description": "Permission code enum representing all available permissions in the system",
        "enum": [
          "organization.update",
          "organization.view",
          "member.view",
          "member.invite",
          "member.remove",
          "member.update_role",
          "project.read",
          "project.create",
          "project.update",
          "project.delete",
          "build.view",
          "build.delete",
          "sdk_key.view",
          "sdk_key.create",
          "sdk_key.delete",
          "private_api_key.view",
          "private_api_key.create",
          "private_api_key.delete",
          "environment.view",
          "environment.create",
          "environment.update",
          "environment.delete",
          "in_app_message.view",
          "in_app_message.create",
          "in_app_message.update",
          "in_app_message.delete",
          "event.view",
          "event.create",
          "event.update",
          "event.delete",
          "ota.view",
          "ota.create",
          "ota.update",
          "ota.delete",
          "analytics.view",
          "support.operations",
          "webhook.view",
          "webhook.create",
          "webhook.update",
          "webhook.delete",
          "feature_flag.view",
          "feature_flag.create",
          "feature_flag.update",
          "feature_flag.delete",
          "audit.read",
          "integration.view",
          "integration.create",
          "integration.update",
          "integration.delete",
          "integration.subscription.view",
          "integration.subscription.create",
          "integration.subscription.update",
          "integration.subscription.delete",
          "billing.subscription.view",
          "billing.subscription.manage",
          "billing.usage.view",
          "billing.entitlements.view",
          "dashboard.view",
          "dashboard.manage",
          "flutter.view",
          "flutter.create",
          "flutter.update",
          "flutter.delete",
          "invitation.cancel",
          "invitation.delete",
          "aivisibility.view",
          "aivisibility.manage",
          "siteaudit.view",
          "siteaudit.manage",
          "engagement.view",
          "engagement.manage",
          "dataimport.view",
          "dataimport.manage",
          "contentrecs.view",
          "contentrecs.manage",
          "backlinks.view",
          "backlinks.manage",
          "marketplace.view",
          "marketplace.order",
          "workflow.view",
          "workflow.manage",
          "workflow.run",
          "contentdraft.view",
          "contentdraft.manage",
          "trackable_actions.view",
          "trackable_actions.manage",
          "keywords.view",
          "keywords.manage"
        ]
      },
      "RoleWithPermissionsResponse": {
        "type": "object",
        "description": "Role information with associated permissions",
        "required": [
          "id",
          "name",
          "permissions"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Role ID"
          },
          "name": {
            "type": "string",
            "description": "Role name"
          },
          "description": {
            "type": "string",
            "description": "Role description"
          },
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionCode"
            },
            "description": "List of permission codes associated with this role"
          }
        }
      },
      "InvitationResponse": {
        "type": "object",
        "description": "Invitation information",
        "required": [
          "id",
          "email",
          "organization",
          "role",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Invitation ID"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email of the invited user"
          },
          "organization": {
            "$ref": "#/components/schemas/OrganizationResponse"
          },
          "role": {
            "$ref": "#/components/schemas/RoleResponse"
          },
          "status": {
            "$ref": "#/components/schemas/InvitationStatusResponse"
          },
          "invitedBy": {
            "$ref": "#/components/schemas/UserResponse"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the invitation was created"
          }
        }
      },
      "InvitationStatusResponse": {
        "type": "object",
        "description": "Invitation status information",
        "required": [
          "id",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Status ID"
          },
          "status": {
            "$ref": "#/components/schemas/InvitationStatusEnum"
          }
        }
      },
      "MemberOrInvitationType": {
        "type": "string",
        "enum": [
          "MEMBER",
          "INVITATION"
        ],
        "description": "Type discriminator for merged member/invitation list"
      },
      "MemberOrInvitationItem": {
        "type": "object",
        "description": "Unified item representing either a member or pending invitation",
        "required": [
          "id",
          "type",
          "email",
          "role",
          "timestamp"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Member ID or Invitation ID"
          },
          "type": {
            "$ref": "#/components/schemas/MemberOrInvitationType"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email of the user (from user record for members, invitation email for invitations)"
          },
          "role": {
            "$ref": "#/components/schemas/RoleResponse"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Enabled at timestamp for members, created at for invitations"
          },
          "user": {
            "$ref": "#/components/schemas/UserResponse",
            "nullable": true,
            "description": "Full user details (only for members, null for invitations)"
          }
        }
      },
      "PaginatedMemberOrInvitationResponse": {
        "type": "object",
        "description": "Paginated merged list of members and pending invitations",
        "required": [
          "data",
          "total",
          "count",
          "itemsPerPage"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MemberOrInvitationItem"
            },
            "description": "Array of members and invitations merged and sorted by timestamp"
          },
          "total": {
            "type": "integer",
            "description": "Total number of items (members + invitations) across all pages"
          },
          "count": {
            "type": "integer",
            "description": "Number of items in this page"
          },
          "itemsPerPage": {
            "type": "integer",
            "description": "Maximum items per page"
          }
        }
      },
      "OrganizationMemberResponse": {
        "type": "object",
        "description": "Organization member information",
        "required": [
          "id",
          "user",
          "role",
          "enabledAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Member ID"
          },
          "user": {
            "$ref": "#/components/schemas/UserResponse"
          },
          "role": {
            "$ref": "#/components/schemas/RoleResponse"
          },
          "enabledAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the member enabled their account"
          }
        }
      },
      "ProjectResponse": {
        "type": "object",
        "description": "Project information",
        "required": [
          "id",
          "projectId",
          "organizationId",
          "name",
          "projectType",
          "createdBy",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Project ID (URL-friendly slug derived from the project name)"
          },
          "projectId": {
            "type": "string",
            "description": "Unique project key identifier (same as id)"
          },
          "organizationId": {
            "type": "string",
            "description": "Organization ID that owns this project"
          },
          "name": {
            "type": "string",
            "description": "Project name"
          },
          "description": {
            "type": "string",
            "description": "Project description"
          },
          "projectType": {
            "$ref": "#/components/schemas/ProjectType"
          },
          "websiteDomain": {
            "type": "string",
            "nullable": true,
            "description": "The project's configured public website domain (registrable eTLD+1), or null when the project has no public website configured."
          },
          "keywordLocationCode": {
            "type": "integer",
            "nullable": true,
            "description": "The project's stored default keyword research market, or null when it has never been set (which reads as 2840, United States)."
          },
          "keywordLanguageCode": {
            "type": "string",
            "nullable": true,
            "description": "The language stored alongside keywordLocationCode, or null (which reads as that market's default language)."
          },
          "createdBy": {
            "type": "string",
            "description": "User ID who created the project"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the project was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the project was last updated"
          }
        }
      },
      "EventsAnalytics": {
        "type": "object",
        "description": "Events analytics data for a project within a time period",
        "required": [
          "totalEvents",
          "uniqueUsers"
        ],
        "properties": {
          "totalEvents": {
            "type": "integer",
            "format": "int64",
            "description": "Total number of events logged in the specified period"
          },
          "uniqueUsers": {
            "type": "integer",
            "format": "int64",
            "description": "Total number of unique users in the specified period"
          }
        }
      },
      "ProjectSettingsResponse": {
        "type": "object",
        "description": "Project-level settings: data collection (server enforcement + SDK autocapture) and reporting.",
        "required": [
          "eventsEnabled",
          "ipLoggingEnabled",
          "botDetectionEnabled",
          "autoTrackPageViews",
          "autoTrackOutboundLinks",
          "autoTrackClicks",
          "autoTrackScrollDepth",
          "autoTrackVisibility",
          "reportingTimezone"
        ],
        "properties": {
          "eventsEnabled": {
            "type": "boolean",
            "description": "Whether event ingestion is enabled for the project."
          },
          "ipLoggingEnabled": {
            "type": "boolean",
            "description": "Whether client IP addresses are stored on events."
          },
          "botDetectionEnabled": {
            "type": "boolean",
            "description": "Whether detected bot traffic is dropped before ingestion."
          },
          "autoTrackPageViews": {
            "type": "boolean",
            "description": "SDK autocapture of page views."
          },
          "autoTrackOutboundLinks": {
            "type": "boolean",
            "description": "SDK autocapture of outbound link clicks."
          },
          "autoTrackClicks": {
            "type": "boolean",
            "description": "SDK autocapture of element clicks."
          },
          "autoTrackScrollDepth": {
            "type": "boolean",
            "description": "SDK autocapture of scroll depth."
          },
          "autoTrackVisibility": {
            "type": "boolean",
            "description": "SDK autocapture of element visibility."
          },
          "reportingTimezone": {
            "type": "string",
            "example": "Africa/Cairo",
            "description": "IANA timezone every analytics date boundary for this project is resolved in — presets (\"last 7 days\"), from/to days, and time-series buckets. Server-held, so the dashboard, the assistant, the API, and exports all describe the same period identically. Defaults to UTC."
          }
        }
      },
      "UpdateProjectSettingsRequest": {
        "type": "object",
        "description": "Partial update of project settings. Only provided fields are changed.",
        "properties": {
          "eventsEnabled": {
            "type": "boolean"
          },
          "ipLoggingEnabled": {
            "type": "boolean"
          },
          "botDetectionEnabled": {
            "type": "boolean"
          },
          "autoTrackPageViews": {
            "type": "boolean"
          },
          "autoTrackOutboundLinks": {
            "type": "boolean"
          },
          "autoTrackClicks": {
            "type": "boolean"
          },
          "autoTrackScrollDepth": {
            "type": "boolean"
          },
          "autoTrackVisibility": {
            "type": "boolean"
          },
          "reportingTimezone": {
            "type": "string",
            "example": "Africa/Cairo",
            "description": "IANA timezone id, e.g. \"Africa/Cairo\" or \"UTC\". Rejected with VAL_001 if it is not a zone the server knows."
          }
        }
      },
      "ProjectAnalyticsResponse": {
        "type": "object",
        "description": "Project analytics data including events and storage metrics",
        "required": [
          "projectId",
          "events"
        ],
        "properties": {
          "projectId": {
            "type": "string",
            "description": "Project key identifier"
          },
          "events": {
            "$ref": "#/components/schemas/EventsAnalytics"
          }
        }
      },
      "PaginatedSdkKeyResponse": {
        "type": "object",
        "description": "Paginated SDK key response",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SdkKeyResponse"
            },
            "description": "Array of SDK keys for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of SDK keys"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "CreateSdkKeyRequest": {
        "type": "object",
        "description": "Request to create an SDK key",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Name/description for the SDK key"
          }
        }
      },
      "SdkKeyResponse": {
        "type": "object",
        "description": "SDK key information",
        "required": [
          "id",
          "name",
          "apiKey",
          "projectId",
          "createdBy",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the SDK key"
          },
          "name": {
            "type": "string",
            "description": "Name/description of the SDK key"
          },
          "key": {
            "type": "string",
            "description": "The actual SDK key (only returned on creation)"
          },
          "apiKey": {
            "type": "string",
            "description": "Full SDK key (not masked since keys are public)"
          },
          "projectId": {
            "type": "string",
            "description": "Project ID this SDK key is for"
          },
          "createdBy": {
            "type": "string",
            "description": "User ID who created the key"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the key was last used"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the key was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the key was last updated"
          }
        }
      },
      "CreatePrivateApiKeyRequest": {
        "type": "object",
        "description": "Request to create a private API key (project-scoped)",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Name/description for the private API key"
          }
        }
      },
      "PrivateApiKeyResponse": {
        "type": "object",
        "description": "Private API key information (project-scoped, key is hashed, only shown once on creation)",
        "required": [
          "id",
          "name",
          "projectId",
          "createdBy",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the private API key"
          },
          "name": {
            "type": "string",
            "description": "Name/description of the private API key"
          },
          "key": {
            "type": "string",
            "description": "The actual private API key (only returned on creation, never stored)"
          },
          "keyPrefix": {
            "type": "string",
            "description": "Masked key prefix for display (e.g., sk_kitbase_abc...xyz)"
          },
          "projectId": {
            "type": "string",
            "description": "Project ID this private API key is for"
          },
          "createdBy": {
            "type": "string",
            "description": "User ID who created the key"
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the key was last used"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the key was created"
          }
        }
      },
      "PaginatedPrivateApiKeyResponse": {
        "type": "object",
        "description": "Paginated private API key response",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrivateApiKeyResponse"
            },
            "description": "Array of private API keys for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of private API keys"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "MessageType": {
        "type": "string",
        "enum": [
          "modal",
          "banner",
          "card",
          "image"
        ]
      },
      "InAppMessageResponse": {
        "type": "object",
        "required": [
          "id",
          "name",
          "title",
          "message",
          "showOnce",
          "messageType",
          "isActive",
          "projectId",
          "viewCount",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "showOnce": {
            "type": "boolean"
          },
          "messageType": {
            "$ref": "#/components/schemas/MessageType"
          },
          "isActive": {
            "type": "boolean"
          },
          "imageUrl": {
            "type": "string"
          },
          "actionButtonText": {
            "type": "string"
          },
          "actionButtonUrl": {
            "type": "string"
          },
          "secondaryButtonText": {
            "type": "string"
          },
          "secondaryButtonUrl": {
            "type": "string"
          },
          "backgroundColor": {
            "type": "string"
          },
          "actionButtonColor": {
            "type": "string"
          },
          "actionButtonTextColor": {
            "type": "string"
          },
          "secondaryButtonColor": {
            "type": "string"
          },
          "secondaryButtonTextColor": {
            "type": "string"
          },
          "borderRadius": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ],
            "default": "medium"
          },
          "shadow": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ],
            "default": "medium"
          },
          "targetingConditions": {
            "$ref": "#/components/schemas/TargetingConditions"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time"
          },
          "projectId": {
            "type": "string"
          },
          "createdBy": {
            "type": "string"
          },
          "viewCount": {
            "type": "integer"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateInAppMessageRequest": {
        "type": "object",
        "required": [
          "name",
          "title",
          "message"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 500
          },
          "message": {
            "type": "string",
            "description": "Markdown content"
          },
          "showOnce": {
            "type": "boolean",
            "default": false
          },
          "messageType": {
            "$ref": "#/components/schemas/MessageType"
          },
          "isActive": {
            "type": "boolean",
            "default": true
          },
          "imageUrl": {
            "type": "string",
            "maxLength": 2048
          },
          "actionButtonText": {
            "type": "string",
            "maxLength": 255
          },
          "actionButtonUrl": {
            "type": "string",
            "maxLength": 2048
          },
          "secondaryButtonText": {
            "type": "string",
            "maxLength": 255
          },
          "secondaryButtonUrl": {
            "type": "string",
            "maxLength": 2048
          },
          "backgroundColor": {
            "type": "string",
            "pattern": "^#[0-9a-fA-F]{6}$"
          },
          "actionButtonColor": {
            "type": "string",
            "maxLength": 7
          },
          "actionButtonTextColor": {
            "type": "string",
            "maxLength": 7
          },
          "secondaryButtonColor": {
            "type": "string",
            "maxLength": 7
          },
          "secondaryButtonTextColor": {
            "type": "string",
            "maxLength": 7
          },
          "borderRadius": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ]
          },
          "shadow": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ]
          },
          "targetingConditions": {
            "$ref": "#/components/schemas/TargetingConditions"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UpdateInAppMessageRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "title": {
            "type": "string",
            "maxLength": 500
          },
          "message": {
            "type": "string"
          },
          "showOnce": {
            "type": "boolean"
          },
          "messageType": {
            "$ref": "#/components/schemas/MessageType"
          },
          "isActive": {
            "type": "boolean"
          },
          "imageUrl": {
            "type": "string",
            "maxLength": 2048
          },
          "actionButtonText": {
            "type": "string",
            "maxLength": 255
          },
          "actionButtonUrl": {
            "type": "string",
            "maxLength": 2048
          },
          "secondaryButtonText": {
            "type": "string",
            "maxLength": 255
          },
          "secondaryButtonUrl": {
            "type": "string",
            "maxLength": 2048
          },
          "backgroundColor": {
            "type": "string",
            "pattern": "^#[0-9a-fA-F]{6}$"
          },
          "actionButtonColor": {
            "type": "string",
            "maxLength": 7
          },
          "actionButtonTextColor": {
            "type": "string",
            "maxLength": 7
          },
          "secondaryButtonColor": {
            "type": "string",
            "maxLength": 7
          },
          "secondaryButtonTextColor": {
            "type": "string",
            "maxLength": 7
          },
          "borderRadius": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ]
          },
          "shadow": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ]
          },
          "targetingConditions": {
            "$ref": "#/components/schemas/TargetingConditions"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginatedInAppMessageResponse": {
        "type": "object",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InAppMessageResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "InAppMessageViewResponse": {
        "type": "object",
        "required": [
          "id",
          "messageId",
          "userId",
          "viewedAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "messageId": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "viewedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginatedInAppMessageViewResponse": {
        "type": "object",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InAppMessageViewResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "AuditLogResponse": {
        "description": "Audit log entry - type varies based on action",
        "oneOf": [
          {
            "$ref": "#/components/schemas/SdkKeyCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/SdkKeyDeletedAuditLog"
          },
          {
            "$ref": "#/components/schemas/PrivateApiKeyCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/PrivateApiKeyDeletedAuditLog"
          },
          {
            "$ref": "#/components/schemas/ProjectCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/ProjectUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/ProjectDeletedAuditLog"
          },
          {
            "$ref": "#/components/schemas/InAppMessageCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/InAppMessageUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/InAppMessageDeletedAuditLog"
          },
          {
            "$ref": "#/components/schemas/FeatureFlagCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/FeatureFlagUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/FeatureFlagDeletedAuditLog"
          },
          {
            "$ref": "#/components/schemas/FeatureFlagRulesUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/SegmentCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/SegmentUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/SegmentDeletedAuditLog"
          },
          {
            "$ref": "#/components/schemas/WebhookCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/WebhookUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/WebhookDeletedAuditLog"
          },
          {
            "$ref": "#/components/schemas/InvitationCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/InvitationAcceptedAuditLog"
          },
          {
            "$ref": "#/components/schemas/InvitationCanceledAuditLog"
          },
          {
            "$ref": "#/components/schemas/InvitationRevokedAuditLog"
          },
          {
            "$ref": "#/components/schemas/MemberRemovedAuditLog"
          },
          {
            "$ref": "#/components/schemas/MemberRoleUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/OrganizationCreatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/OrganizationUpdatedAuditLog"
          },
          {
            "$ref": "#/components/schemas/UserLoginSuccessAuditLog"
          },
          {
            "$ref": "#/components/schemas/UserLoginFailedAuditLog"
          },
          {
            "$ref": "#/components/schemas/PasswordChangedAuditLog"
          },
          {
            "$ref": "#/components/schemas/LogRateExceededAuditLog"
          },
          {
            "$ref": "#/components/schemas/GenericAuditLog"
          }
        ]
      },
      "AuditLogBase": {
        "type": "object",
        "required": [
          "id",
          "action",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the audit log entry"
          },
          "userId": {
            "type": "string",
            "description": "ID of the user who performed the action"
          },
          "organizationId": {
            "type": "string",
            "description": "ID of the organization"
          },
          "action": {
            "type": "string",
            "description": "Action performed"
          },
          "resourceType": {
            "type": "string",
            "description": "Type of resource affected"
          },
          "resourceId": {
            "type": "string",
            "description": "ID of the affected resource"
          },
          "resourceName": {
            "type": "string",
            "description": "Name of the affected resource"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the action occurred"
          }
        }
      },
      "SdkKeyCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "SDK_KEY_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "SDK_KEY"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/SdkKeyCreatedMetadata"
              }
            }
          }
        ]
      },
      "SdkKeyCreatedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "apiKey": {
                "type": "string"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "SdkKeyDeletedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "SDK_KEY_DELETED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "SDK_KEY"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/SdkKeyDeletedMetadata"
              }
            }
          }
        ]
      },
      "SdkKeyDeletedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "apiKey": {
                "type": "string"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "PrivateApiKeyCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "PRIVATE_API_KEY_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "PRIVATE_API_KEY"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/PrivateApiKeyCreatedMetadata"
              }
            }
          }
        ]
      },
      "PrivateApiKeyCreatedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "keyPrefix": {
                "type": "string"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "PrivateApiKeyDeletedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "PRIVATE_API_KEY_DELETED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "PRIVATE_API_KEY"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/PrivateApiKeyDeletedMetadata"
              }
            }
          }
        ]
      },
      "PrivateApiKeyDeletedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "keyPrefix": {
                "type": "string"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "ProjectCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "PROJECT_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "PROJECT"
                ]
              }
            }
          }
        ]
      },
      "ProjectUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "PROJECT_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "PROJECT"
                ]
              }
            }
          }
        ]
      },
      "ProjectDeletedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "PROJECT_DELETED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "PROJECT"
                ]
              }
            }
          }
        ]
      },
      "InAppMessageCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "IN_APP_MESSAGE_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "IN_APP_MESSAGE"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/InAppMessageCreatedMetadata"
              }
            }
          }
        ]
      },
      "InAppMessageCreatedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "isActive": {
                "type": "boolean"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "InAppMessageUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "IN_APP_MESSAGE_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "IN_APP_MESSAGE"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/InAppMessageUpdatedMetadata"
              }
            }
          }
        ]
      },
      "InAppMessageUpdatedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "isActive": {
                "type": "boolean"
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "isActive": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "InAppMessageDeletedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "IN_APP_MESSAGE_DELETED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "IN_APP_MESSAGE"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/InAppMessageDeletedMetadata"
              }
            }
          }
        ]
      },
      "InAppMessageDeletedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "isActive": {
                "type": "boolean"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "FeatureFlagCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/FeatureFlagCreatedMetadata"
              }
            }
          }
        ]
      },
      "FeatureFlagCreatedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "flagKey": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "valueType": {
                "type": "string"
              },
              "enabled": {
                "type": "boolean"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "FeatureFlagUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/FeatureFlagUpdatedMetadata"
              }
            }
          }
        ]
      },
      "FeatureFlagUpdatedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "enabled": {
                "type": "boolean"
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "enabled": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "FeatureFlagDeletedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG_DELETED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG"
                ]
              }
            }
          }
        ]
      },
      "FeatureFlagRulesUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG_RULES_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "FEATURE_FLAG"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/FeatureFlagRulesUpdatedMetadata"
              }
            }
          }
        ]
      },
      "FeatureFlagRulesUpdatedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "ruleCount": {
                "type": "integer"
              },
              "rules": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "ruleCount": {
                "type": "integer"
              },
              "rules": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "SegmentCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "SEGMENT_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "SEGMENT"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/SegmentCreatedMetadata"
              }
            }
          }
        ]
      },
      "SegmentCreatedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "key": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "SegmentUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "SEGMENT_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "SEGMENT"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/SegmentUpdatedMetadata"
              }
            }
          }
        ]
      },
      "SegmentUpdatedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "matchType": {
                "type": "string"
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "matchType": {
                "type": "string"
              }
            }
          }
        }
      },
      "SegmentDeletedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "SEGMENT_DELETED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "SEGMENT"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/SegmentDeletedMetadata"
              }
            }
          }
        ]
      },
      "SegmentDeletedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "key": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "projectId": {
                "type": "string"
              }
            }
          }
        }
      },
      "WebhookCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "WEBHOOK_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "WEBHOOK"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/WebhookCreatedMetadata"
              }
            }
          }
        ]
      },
      "WebhookCreatedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "enabled": {
                "type": "boolean"
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "WebhookUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "WEBHOOK_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "WEBHOOK"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/WebhookUpdatedMetadata"
              }
            }
          }
        ]
      },
      "WebhookUpdatedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "enabled": {
                "type": "boolean"
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "enabled": {
                "type": "boolean"
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "WebhookDeletedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "WEBHOOK_DELETED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "WEBHOOK"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/WebhookDeletedMetadata"
              }
            }
          }
        ]
      },
      "WebhookDeletedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "enabled": {
                "type": "boolean"
              },
              "events": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "InvitationCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "INVITATION_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "INVITATION"
                ]
              }
            }
          }
        ]
      },
      "InvitationAcceptedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "INVITATION_ACCEPTED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "INVITATION"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/InvitationAcceptedMetadata"
              }
            }
          }
        ]
      },
      "InvitationAcceptedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string"
              },
              "roleId": {
                "type": "string"
              },
              "roleName": {
                "type": "string"
              },
              "acceptedByUserId": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      },
      "InvitationCanceledAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "INVITATION_CANCELED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "INVITATION"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/InvitationCanceledMetadata"
              }
            }
          }
        ]
      },
      "InvitationCanceledMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string"
              },
              "roleId": {
                "type": "string"
              },
              "roleName": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string"
              }
            }
          }
        }
      },
      "InvitationRevokedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "INVITATION_REVOKED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "INVITATION"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/InvitationRevokedMetadata"
              }
            }
          }
        ]
      },
      "InvitationRevokedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string"
              },
              "roleId": {
                "type": "string"
              },
              "roleName": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      },
      "MemberRemovedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "MEMBER_REMOVED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "MEMBER"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/MemberRemovedMetadata"
              }
            }
          }
        ]
      },
      "MemberRemovedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "userId": {
                "type": "string"
              },
              "email": {
                "type": "string"
              },
              "roleId": {
                "type": "string"
              },
              "roleName": {
                "type": "string"
              }
            }
          }
        }
      },
      "MemberRoleUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "MEMBER_ROLE_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "MEMBER"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/MemberRoleUpdatedMetadata"
              }
            }
          }
        ]
      },
      "MemberRoleUpdatedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "roleId": {
                "type": "string"
              },
              "roleName": {
                "type": "string"
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "roleId": {
                "type": "string"
              },
              "roleName": {
                "type": "string"
              }
            }
          }
        }
      },
      "OrganizationCreatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "ORGANIZATION_CREATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "ORGANIZATION"
                ]
              }
            }
          }
        ]
      },
      "OrganizationUpdatedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "ORGANIZATION_UPDATED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "ORGANIZATION"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/OrganizationUpdatedMetadata"
              }
            }
          }
        ]
      },
      "OrganizationUpdatedMetadata": {
        "type": "object",
        "properties": {
          "before": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "orgSlug": {
                "type": "string"
              }
            }
          },
          "after": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string"
              },
              "orgSlug": {
                "type": "string"
              }
            }
          }
        }
      },
      "UserLoginSuccessAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "USER_LOGIN_SUCCESS"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "USER"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/UserLoginMetadata"
              }
            }
          }
        ]
      },
      "UserLoginFailedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "USER_LOGIN_FAILED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "USER"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/UserLoginFailedMetadata"
              }
            }
          }
        ]
      },
      "UserLoginMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string"
              },
              "ipAddress": {
                "type": "string"
              },
              "userAgent": {
                "type": "string"
              },
              "success": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "UserLoginFailedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string"
              },
              "ipAddress": {
                "type": "string"
              },
              "userAgent": {
                "type": "string"
              },
              "success": {
                "type": "boolean"
              },
              "failureReason": {
                "type": "string"
              }
            }
          }
        }
      },
      "PasswordChangedAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "PASSWORD_CHANGED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "USER"
                ]
              },
              "metadata": {
                "$ref": "#/components/schemas/PasswordChangedMetadata"
              }
            }
          }
        ]
      },
      "PasswordChangedMetadata": {
        "type": "object",
        "properties": {
          "after": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string"
              },
              "changeType": {
                "type": "string",
                "description": "Type of password change (self_change, reset, admin_reset)"
              },
              "ipAddress": {
                "type": "string"
              }
            }
          }
        }
      },
      "LogRateExceededAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "LOG_RATE_EXCEEDED"
                ]
              },
              "resourceType": {
                "type": "string",
                "enum": [
                  "PROJECT"
                ]
              }
            }
          }
        ]
      },
      "GenericAuditLog": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AuditLogBase"
          },
          {
            "type": "object",
            "properties": {
              "metadata": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        ]
      },
      "PaginatedAuditLogResponse": {
        "type": "object",
        "description": "Paginated audit log response",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditLogResponse"
            },
            "description": "List of audit log entries"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Number of items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of audit log entries"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "NotificationResponse": {
        "type": "object",
        "description": "Notification information",
        "required": [
          "id",
          "type",
          "title",
          "isRead",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Notification ID"
          },
          "type": {
            "$ref": "#/components/schemas/NotificationTypeEnum"
          },
          "title": {
            "type": "string",
            "description": "Notification title"
          },
          "message": {
            "type": "string",
            "description": "Notification message body"
          },
          "isRead": {
            "type": "boolean",
            "description": "Whether the notification has been read"
          },
          "resourceId": {
            "type": "string",
            "description": "ID of the related resource (invitation_id, build_id, etc.)"
          },
          "payload": {
            "type": "object",
            "additionalProperties": true,
            "description": "Structured, type-specific content for this notification, at the grain of this row — the data the title and message were rendered from. Shape varies by type and is not part of this contract: clients must render it defensively and fall back to `message`. Absent on rows written before the payload column existed, and on types that carry nothing beyond their text.\n"
          },
          "organizationId": {
            "type": "string",
            "description": "Organization this notification belongs to. Absent means account-level (an invitation to an org you are not yet a member of, an admin broadcast) — those are returned in every organization's list.\n"
          },
          "projectId": {
            "type": "string",
            "description": "Project this notification belongs to, when it has one"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the notification was created"
          }
        }
      },
      "UnreadNotificationCountResponse": {
        "type": "object",
        "description": "Unread notification count for the notification bell badge",
        "required": [
          "unreadCount"
        ],
        "properties": {
          "unreadCount": {
            "type": "integer",
            "description": "Number of unread notifications visible in this organization"
          }
        }
      },
      "PaginatedNotificationResponse": {
        "type": "object",
        "description": "Paginated notification response with unread count",
        "required": [
          "data",
          "unreadCount",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotificationResponse"
            },
            "description": "Array of notifications for this page"
          },
          "unreadCount": {
            "type": "integer",
            "description": "Total number of unread notifications"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Number of items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of notifications"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Standardized error response",
        "required": [
          "error",
          "timestamp"
        ],
        "properties": {
          "error": {
            "type": "object",
            "description": "Error information",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable, machine-readable identifier for this failure (AUTH_*, PERM_*, VAL_*, ORG_*, PROJECT_*, ...). Branch on this, never on the message.",
                "example": "AUTH_001"
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation. Written for people, not for parsers - the wording may change at any time without a version bump.",
                "example": "Invalid credentials"
              },
              "details": {
                "type": "object",
                "description": "Typed extras that annotate the failure, keyed by name. Known keys include `field` and `value` (which input was rejected), `resource` (what was not found), `retryAfterSeconds` (how long a rate-limited caller must wait), `remainingAttempts` and `reason`. Absent when the code alone says everything.",
                "additionalProperties": true,
                "example": {
                  "field": "email",
                  "value": "user@example.com"
                }
              },
              "stackTrace": {
                "type": "string",
                "description": "Stack trace of the exception (only included in development mode)",
                "example": "java.lang.RuntimeException: Test error\n\tat com.app.server.service.UserService.method(UserService.java:123)"
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the error occurred"
          }
        }
      },
      "LogEventRequest": {
        "type": "object",
        "description": "Request to log a custom event from SDK",
        "required": [
          "event"
        ],
        "properties": {
          "event": {
            "type": "string",
            "description": "Event name",
            "example": "New Subscription"
          },
          "channel": {
            "type": "string",
            "description": "Optional channel/category for grouping events",
            "example": "payments"
          },
          "user_id": {
            "type": "string",
            "description": "External user identifier from client system (set when user is identified/logged in)",
            "example": "user-123"
          },
          "icon": {
            "type": "string",
            "description": "Emoji icon for the event",
            "example": "💰"
          },
          "notify": {
            "type": "boolean",
            "description": "Whether to trigger notifications",
            "default": false
          },
          "description": {
            "type": "string",
            "description": "Optional event description",
            "example": "User subscribed to premium plan"
          },
          "tags": {
            "type": "object",
            "description": "Key-value metadata for the event",
            "additionalProperties": true,
            "example": {
              "plan": "premium",
              "cycle": "monthly",
              "trial": false
            }
          },
          "client_timestamp": {
            "type": "integer",
            "format": "int64",
            "description": "Client-side timestamp for offline-queued events (epoch milliseconds)",
            "example": 1768666153270
          },
          "client_session_id": {
            "type": "string",
            "description": "Marks events replayed from the SDK's offline queue; absent on live events. Sessions are resolved server-side (opened on the first event, closed after 30 minutes of inactivity), so this is a hint about origin, not a session identity — it lives in the SDK's memory and changes on every page load, app restart and extra tab.",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          "sdk_version": {
            "type": "string",
            "description": "Version of the Kitbase SDK package that produced this event",
            "example": "0.1.8"
          }
        }
      },
      "LogEventResponse": {
        "type": "object",
        "description": "Response after logging an event",
        "required": [
          "id",
          "event",
          "timestamp"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event identifier"
          },
          "event": {
            "type": "string",
            "description": "Event name"
          },
          "timestamp": {
            "type": "integer",
            "format": "int64",
            "description": "When the event was recorded as epoch milliseconds"
          }
        }
      },
      "BatchLogEventRequest": {
        "type": "object",
        "description": "Request to log a batch of events from SDK",
        "required": [
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LogEventRequest"
            },
            "maxItems": 500,
            "description": "List of events to log (max 500)"
          }
        }
      },
      "BatchLogEventResponse": {
        "type": "object",
        "description": "Response after logging a batch of events",
        "required": [
          "accepted",
          "total"
        ],
        "properties": {
          "accepted": {
            "type": "integer",
            "description": "Number of events accepted for processing"
          },
          "total": {
            "type": "integer",
            "description": "Total number of events in the batch"
          }
        }
      },
      "ServerObservedRequest": {
        "type": "object",
        "description": "A single end-user request observed by the customer's server/edge middleware, forwarded so the backend can classify the actor (bot/crawler) server-side. Carries the ORIGINAL visitor's signals (not the middleware's connection), so non-JS crawlers — which never run the SDK — are captured. Human (non-bot) requests are ignored here to avoid double-counting the JS SDK.",
        "required": [
          "user_agent",
          "ip_address"
        ],
        "properties": {
          "user_agent": {
            "type": "string",
            "description": "The original request's User-Agent header"
          },
          "ip_address": {
            "type": "string",
            "description": "The original client IP (as resolved by the customer's edge/server)"
          },
          "method": {
            "type": "string",
            "description": "HTTP method of the original request (for Web Bot Auth signature base)",
            "example": "GET"
          },
          "host": {
            "type": "string",
            "description": "Host/authority of the original request",
            "example": "example.com"
          },
          "path": {
            "type": "string",
            "description": "Path of the original request",
            "example": "/pricing"
          },
          "referrer": {
            "type": "string",
            "description": "Referer header of the original request"
          },
          "signature": {
            "type": "string",
            "description": "Web Bot Auth Signature header, if present (enables cryptographic verification)"
          },
          "signature_input": {
            "type": "string",
            "description": "Web Bot Auth Signature-Input header, if present"
          },
          "signature_agent": {
            "type": "string",
            "description": "Web Bot Auth Signature-Agent header, if present"
          },
          "client_timestamp": {
            "type": "integer",
            "format": "int64",
            "description": "When the request was observed (epoch milliseconds); defaults to receipt time"
          },
          "event": {
            "type": "string",
            "description": "Event name to record; defaults to \"server_request\"",
            "example": "server_request"
          }
        }
      },
      "ServerEventBatchRequest": {
        "type": "object",
        "description": "A batch of server-observed requests for crawler/bot attribution.",
        "required": [
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServerObservedRequest"
            },
            "maxItems": 500,
            "description": "List of observed requests (max 500)"
          }
        }
      },
      "IdentifyRequest": {
        "type": "object",
        "description": "Request to identify a user. Server derives anonymous_id from request context (User-Agent + IP + salt).",
        "required": [
          "user_id"
        ],
        "properties": {
          "user_id": {
            "type": "string",
            "description": "External user identifier from client system (e.g., database user ID)",
            "example": "user-123"
          },
          "traits": {
            "type": "object",
            "description": "Optional user traits/properties to store",
            "additionalProperties": true,
            "example": {
              "email": "user@example.com",
              "plan": "premium",
              "created_at": "2024-01-15"
            }
          }
        }
      },
      "IdentifyResponse": {
        "type": "object",
        "description": "Response after identifying a user",
        "required": [
          "success",
          "user_id"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the identity was linked successfully"
          },
          "user_id": {
            "type": "string",
            "description": "The user ID that was linked"
          }
        }
      },
      "SdkInAppMessageResponse": {
        "type": "object",
        "required": [
          "id",
          "title",
          "message",
          "showOnce",
          "messageType"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "message": {
            "type": "string",
            "description": "Markdown content"
          },
          "showOnce": {
            "type": "boolean"
          },
          "messageType": {
            "type": "string",
            "enum": [
              "modal",
              "banner",
              "card",
              "image"
            ]
          },
          "imageUrl": {
            "type": "string"
          },
          "actionButtonText": {
            "type": "string"
          },
          "actionButtonUrl": {
            "type": "string"
          },
          "secondaryButtonText": {
            "type": "string"
          },
          "secondaryButtonUrl": {
            "type": "string"
          },
          "backgroundColor": {
            "type": "string"
          },
          "actionButtonColor": {
            "type": "string"
          },
          "actionButtonTextColor": {
            "type": "string"
          },
          "secondaryButtonColor": {
            "type": "string"
          },
          "secondaryButtonTextColor": {
            "type": "string"
          },
          "borderRadius": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ],
            "default": "medium"
          },
          "shadow": {
            "type": "string",
            "enum": [
              "none",
              "small",
              "medium",
              "large"
            ],
            "default": "medium"
          },
          "startDate": {
            "type": "string",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SdkActiveMessagesResponse": {
        "type": "object",
        "required": [
          "messages"
        ],
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SdkInAppMessageResponse"
            }
          }
        }
      },
      "RecordMessageViewRequest": {
        "type": "object",
        "required": [
          "messageId",
          "userId"
        ],
        "properties": {
          "messageId": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          }
        }
      },
      "KeyInfoResponse": {
        "type": "object",
        "description": "API key context information (secret keys are project-scoped)",
        "required": [
          "projectId",
          "organizationId",
          "orgSlug"
        ],
        "properties": {
          "projectId": {
            "type": "string",
            "description": "Project ID associated with the API key"
          },
          "organizationId": {
            "type": "string",
            "description": "Organization ID associated with the API key"
          },
          "orgSlug": {
            "type": "string",
            "description": "Organization slug for URL construction"
          }
        }
      },
      "CliAuthSessionCreateRequest": {
        "type": "object",
        "required": [
          "deviceName"
        ],
        "properties": {
          "deviceName": {
            "type": "string",
            "maxLength": 255,
            "description": "Hostname/user of the machine running the CLI, shown on the approval page",
            "example": "jane@MacBook-Pro"
          },
          "clientVersion": {
            "type": "string",
            "maxLength": 50,
            "example": "0.1.0"
          },
          "loopbackPort": {
            "type": "integer",
            "minimum": 1024,
            "maximum": 65535,
            "description": "Local port the CLI is listening on for the instant wake-up ping"
          },
          "state": {
            "type": "string",
            "maxLength": 64,
            "description": "CLI-generated nonce echoed on the loopback wake-up so the CLI can verify origin"
          }
        }
      },
      "CliAuthSessionCreateResponse": {
        "type": "object",
        "required": [
          "sessionId",
          "userCode",
          "pollSecret",
          "verificationUrl",
          "expiresAt",
          "pollIntervalSeconds"
        ],
        "properties": {
          "sessionId": {
            "type": "string",
            "format": "uuid"
          },
          "userCode": {
            "type": "string",
            "description": "Short code the CLI must display; the user types it on the approval page",
            "example": "WDJB-MJHT"
          },
          "pollSecret": {
            "type": "string",
            "description": "High-entropy secret held only by the CLI; required to retrieve tokens"
          },
          "verificationUrl": {
            "type": "string",
            "description": "Dashboard URL to open in the browser",
            "example": "https://app.kitbase.dev/cli/authorize?session=7f6c1e2a-..."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "pollIntervalSeconds": {
            "type": "integer",
            "example": 5
          }
        }
      },
      "CliAuthSessionResponse": {
        "type": "object",
        "required": [
          "sessionId",
          "status",
          "deviceName",
          "createdAt",
          "expiresAt"
        ],
        "properties": {
          "sessionId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "denied",
              "consumed",
              "expired"
            ]
          },
          "deviceName": {
            "type": "string"
          },
          "clientVersion": {
            "type": "string"
          },
          "ipAddress": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CliAuthSessionApproveRequest": {
        "type": "object",
        "required": [
          "userCode"
        ],
        "properties": {
          "userCode": {
            "type": "string",
            "description": "The code displayed in the user's terminal"
          }
        }
      },
      "CliAuthSessionApproveResponse": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "approved"
            ]
          },
          "loopbackUrl": {
            "type": "string",
            "nullable": true,
            "description": "If the CLI registered a loopback port, the URL the page should ping (fire-and-forget) to wake the CLI, e.g. http://127.0.0.1:51234/callback?state=..."
          }
        }
      },
      "CliAuthTokenRequest": {
        "type": "object",
        "required": [
          "pollSecret"
        ],
        "properties": {
          "pollSecret": {
            "type": "string"
          }
        }
      },
      "CliAuthTokenPendingResponse": {
        "type": "object",
        "required": [
          "status",
          "pollIntervalSeconds"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending"
            ]
          },
          "pollIntervalSeconds": {
            "type": "integer"
          }
        }
      },
      "CliAuthTokenResponse": {
        "type": "object",
        "required": [
          "accessToken",
          "refreshToken"
        ],
        "properties": {
          "accessToken": {
            "type": "string"
          },
          "refreshToken": {
            "type": "string"
          },
          "refreshTokenExpiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "user": {
            "$ref": "#/components/schemas/UserResponse"
          }
        }
      },
      "CustomEvent": {
        "description": "A tracked event. The schema varies based on the event type. Auto-tracked events (screen_view, click, outbound_link, scroll_depth, revenue) use the __analytics channel and have typed tags. Data-attribute events use a user-specified channel. All other events are returned as GenericCustomEvent.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/ScreenViewEvent"
          },
          {
            "$ref": "#/components/schemas/ClickEvent"
          },
          {
            "$ref": "#/components/schemas/OutboundLinkEvent"
          },
          {
            "$ref": "#/components/schemas/ScrollDepthEvent"
          },
          {
            "$ref": "#/components/schemas/RevenueEvent"
          },
          {
            "$ref": "#/components/schemas/VisibilityEvent"
          },
          {
            "$ref": "#/components/schemas/DataAttributeClickEvent"
          },
          {
            "$ref": "#/components/schemas/GenericCustomEvent"
          }
        ]
      },
      "CustomEventBase": {
        "type": "object",
        "description": "Common fields shared by all event types",
        "required": [
          "id",
          "event",
          "timestamp",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event identifier"
          },
          "event": {
            "type": "string",
            "description": "Event name"
          },
          "channel": {
            "type": "string",
            "description": "Channel/category"
          },
          "userId": {
            "type": "string",
            "description": "External user identifier (set when user is identified/logged in)"
          },
          "anonymousId": {
            "type": "string",
            "description": "SDK-generated persistent identifier for anonymous users"
          },
          "icon": {
            "type": "string",
            "description": "Emoji icon"
          },
          "notify": {
            "type": "boolean",
            "description": "Whether notifications were triggered"
          },
          "description": {
            "type": "string",
            "description": "Event description"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the event occurred"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the event was recorded on server"
          },
          "ipAddress": {
            "type": "string",
            "description": "IP address of the client that sent the event (if IP logging is enabled)"
          },
          "rawUrl": {
            "type": "string",
            "description": "Original URL path as sent from the SDK, before normalization"
          },
          "path": {
            "type": "string",
            "description": "Normalized URL path (UUIDs/IDs replaced with :id)"
          },
          "referrer": {
            "type": "string",
            "description": "Referrer URL"
          },
          "sessionId": {
            "type": "string",
            "description": "Server-generated session identifier"
          },
          "browser": {
            "type": "string",
            "description": "Browser name (e.g. Chrome, Firefox)"
          },
          "browserVersion": {
            "type": "string",
            "description": "Browser version"
          },
          "os": {
            "type": "string",
            "description": "Operating system (e.g. Windows, macOS)"
          },
          "osVersion": {
            "type": "string",
            "description": "Operating system version"
          },
          "device": {
            "type": "string",
            "description": "Device type (e.g. desktop, mobile, tablet)"
          },
          "brand": {
            "type": "string",
            "description": "Device brand (e.g. Apple, Samsung)"
          },
          "model": {
            "type": "string",
            "description": "Device model"
          },
          "country": {
            "type": "string",
            "description": "Country (ISO code from server-side geo-IP lookup)"
          },
          "region": {
            "type": "string",
            "description": "Region/state"
          },
          "city": {
            "type": "string",
            "description": "City"
          },
          "utmSource": {
            "type": "string",
            "description": "UTM source parameter"
          },
          "utmMedium": {
            "type": "string",
            "description": "UTM medium parameter"
          },
          "utmCampaign": {
            "type": "string",
            "description": "UTM campaign parameter"
          },
          "duration": {
            "type": "number",
            "format": "double",
            "description": "Event duration in milliseconds"
          },
          "revenue": {
            "type": "number",
            "format": "double",
            "description": "Revenue value associated with this event"
          },
          "sdkVersion": {
            "type": "string",
            "nullable": true,
            "description": "Version of the Kitbase SDK package that produced this event"
          }
        }
      },
      "ScreenViewEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "properties": {
              "event": {
                "type": "string",
                "enum": [
                  "screen_view"
                ]
              },
              "channel": {
                "type": "string",
                "enum": [
                  "__analytics"
                ]
              },
              "tags": {
                "$ref": "#/components/schemas/ScreenViewTags"
              }
            }
          }
        ]
      },
      "ScreenViewTags": {
        "type": "object",
        "properties": {
          "__path": {
            "type": "string",
            "description": "window.location.pathname"
          },
          "__title": {
            "type": "string",
            "description": "document.title"
          },
          "__referrer": {
            "type": "string",
            "description": "document.referrer"
          },
          "__utm_source": {
            "type": "string",
            "description": "UTM source parameter"
          },
          "__utm_medium": {
            "type": "string",
            "description": "UTM medium parameter"
          },
          "__utm_campaign": {
            "type": "string",
            "description": "UTM campaign parameter"
          },
          "__utm_term": {
            "type": "string",
            "description": "UTM term parameter"
          },
          "__utm_content": {
            "type": "string",
            "description": "UTM content parameter"
          }
        },
        "additionalProperties": true
      },
      "ClickEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "properties": {
              "event": {
                "type": "string",
                "enum": [
                  "click"
                ]
              },
              "channel": {
                "type": "string",
                "enum": [
                  "__analytics"
                ]
              },
              "tags": {
                "$ref": "#/components/schemas/ClickTags"
              }
            }
          }
        ]
      },
      "ClickTags": {
        "type": "object",
        "properties": {
          "__tag": {
            "type": "string",
            "description": "HTML tag name (e.g. button, a, ion-button)"
          },
          "__id": {
            "type": "string",
            "description": "Element id attribute"
          },
          "__class": {
            "type": "string",
            "description": "Element className"
          },
          "__text": {
            "type": "string",
            "description": "Text content (trimmed, max 100 chars)"
          },
          "__href": {
            "type": "string",
            "description": "href attribute (if present)"
          },
          "__path": {
            "type": "string",
            "description": "window.location.pathname"
          }
        },
        "additionalProperties": true
      },
      "OutboundLinkEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "properties": {
              "event": {
                "type": "string",
                "enum": [
                  "outbound_link"
                ]
              },
              "channel": {
                "type": "string",
                "enum": [
                  "__analytics"
                ]
              },
              "tags": {
                "$ref": "#/components/schemas/OutboundLinkTags"
              }
            }
          }
        ]
      },
      "OutboundLinkTags": {
        "type": "object",
        "properties": {
          "__url": {
            "type": "string",
            "description": "Full URL of the external link"
          },
          "__text": {
            "type": "string",
            "description": "Link text content"
          }
        },
        "additionalProperties": true
      },
      "ScrollDepthEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "properties": {
              "event": {
                "type": "string",
                "enum": [
                  "scroll_depth"
                ]
              },
              "channel": {
                "type": "string",
                "enum": [
                  "__analytics"
                ]
              },
              "tags": {
                "$ref": "#/components/schemas/ScrollDepthTags"
              }
            }
          }
        ]
      },
      "ScrollDepthTags": {
        "type": "object",
        "properties": {
          "__depth": {
            "type": "number",
            "description": "Maximum scroll depth as percentage (0-100)"
          },
          "__path": {
            "type": "string",
            "description": "window.location.pathname"
          }
        },
        "additionalProperties": true
      },
      "RevenueEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "properties": {
              "event": {
                "type": "string",
                "enum": [
                  "revenue"
                ]
              },
              "channel": {
                "type": "string",
                "enum": [
                  "__analytics"
                ]
              },
              "tags": {
                "$ref": "#/components/schemas/RevenueTags"
              }
            }
          }
        ]
      },
      "RevenueTags": {
        "type": "object",
        "properties": {
          "__revenue": {
            "type": "number",
            "description": "Revenue amount"
          },
          "__currency": {
            "type": "string",
            "description": "Currency code (e.g. USD, EUR)"
          }
        },
        "additionalProperties": true
      },
      "VisibilityEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "description": "Fired by data-kb-track-visibility when an element leaves the viewport, is removed from the DOM, or the user navigates away. Channel and event name are user-specified via data attributes.",
            "properties": {
              "tags": {
                "$ref": "#/components/schemas/VisibilityTags"
              }
            }
          }
        ]
      },
      "VisibilityTags": {
        "type": "object",
        "properties": {
          "duration_seconds": {
            "type": "number",
            "description": "Total visible time in whole seconds"
          },
          "duration_ms": {
            "type": "number",
            "description": "Total visible time in milliseconds"
          }
        },
        "additionalProperties": true
      },
      "DataAttributeClickEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "description": "Fired by data-kb-track-click when a user clicks an annotated element. Channel and event name are user-specified via data attributes.",
            "properties": {
              "tags": {
                "$ref": "#/components/schemas/DataAttributeClickTags"
              }
            }
          }
        ]
      },
      "DataAttributeClickTags": {
        "type": "object",
        "properties": {
          "__path": {
            "type": "string",
            "description": "window.location.pathname"
          }
        },
        "additionalProperties": true
      },
      "GenericCustomEvent": {
        "allOf": [
          {
            "$ref": "#/components/schemas/CustomEventBase"
          },
          {
            "type": "object",
            "description": "A user-defined custom event that does not match any auto-tracked type",
            "properties": {
              "tags": {
                "type": "object",
                "description": "Key-value metadata",
                "additionalProperties": true
              }
            }
          }
        ]
      },
      "PaginatedCustomEvent": {
        "type": "object",
        "description": "Paginated list of custom events",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomEvent"
            },
            "description": "Array of events for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of items"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "SessionSummary": {
        "type": "object",
        "description": "Aggregated session data from analytics events",
        "required": [
          "sessionId",
          "startedAt",
          "endedAt",
          "entryPage",
          "exitPage",
          "durationSeconds",
          "isBounce",
          "pageViews",
          "eventsCount"
        ],
        "properties": {
          "sessionId": {
            "type": "string",
            "description": "Unique session identifier"
          },
          "userId": {
            "type": "string",
            "nullable": true,
            "description": "Identified user ID, if available"
          },
          "anonymousId": {
            "type": "string",
            "nullable": true,
            "description": "Anonymous user ID"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the first event in this session"
          },
          "endedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the last event in this session"
          },
          "entryPage": {
            "type": "string",
            "nullable": true,
            "description": "First page visited in this session"
          },
          "exitPage": {
            "type": "string",
            "nullable": true,
            "description": "Last page visited in this session"
          },
          "durationSeconds": {
            "type": "number",
            "format": "double",
            "description": "Total session duration in seconds"
          },
          "isBounce": {
            "type": "boolean",
            "description": "Whether this session had only one screen_view event"
          },
          "referrer": {
            "type": "string",
            "nullable": true,
            "description": "Referrer URL for the session entry"
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country of the user"
          },
          "os": {
            "type": "string",
            "nullable": true,
            "description": "Operating system"
          },
          "browser": {
            "type": "string",
            "nullable": true,
            "description": "Browser name"
          },
          "device": {
            "type": "string",
            "nullable": true,
            "description": "Device type"
          },
          "pageViews": {
            "type": "integer",
            "description": "Number of screen_view events in this session"
          },
          "eventsCount": {
            "type": "integer",
            "description": "Total number of events in this session"
          },
          "frustrationScore": {
            "type": "integer",
            "nullable": true,
            "description": "Weighted frustration score for this session (rage_clicks * 3 + dead_clicks). Null if no frustration events."
          }
        }
      },
      "PaginatedSessionResponse": {
        "type": "object",
        "description": "Paginated list of session summaries",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionSummary"
            },
            "description": "Array of sessions for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of sessions"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "BotEventResponse": {
        "type": "object",
        "description": "A single bot/crawler request observation",
        "required": [
          "id",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique event identifier"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the request was observed"
          },
          "eventName": {
            "type": "string",
            "nullable": true,
            "description": "Event name (e.g. server_request)"
          },
          "actorType": {
            "type": "string",
            "nullable": true,
            "description": "verified_bot, spoofed_bot, or suspected_bot"
          },
          "botName": {
            "type": "string",
            "nullable": true,
            "description": "Attributed bot name (e.g. GPTBot)"
          },
          "vendor": {
            "type": "string",
            "nullable": true,
            "description": "Operating vendor (e.g. OpenAI)"
          },
          "category": {
            "type": "string",
            "nullable": true,
            "description": "Functional category (e.g. ai_training, search_engine)"
          },
          "verified": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the bot's identity was cryptographically/network confirmed"
          },
          "verificationMethod": {
            "type": "string",
            "nullable": true,
            "description": "web_bot_auth, cidr, reverse_dns, or none"
          },
          "confidence": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Classification confidence (0.0–1.0)"
          },
          "isAi": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether this is an AI crawler/agent"
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country (from IP)"
          },
          "path": {
            "type": "string",
            "nullable": true,
            "description": "Request path (normalized, no query string)"
          },
          "rawUrl": {
            "type": "string",
            "nullable": true,
            "description": "Full request URL including query string, as observed"
          },
          "referrer": {
            "type": "string",
            "nullable": true,
            "description": "Referrer URL"
          }
        }
      },
      "PaginatedBotEventResponse": {
        "type": "object",
        "description": "Paginated list of bot/crawler requests",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BotEventResponse"
            },
            "description": "Array of bot requests for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of bot requests"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "BotCountryStat": {
        "type": "object",
        "description": "Bot/crawler traffic aggregated for a single country",
        "required": [
          "botCount",
          "requestCount"
        ],
        "properties": {
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country (from IP); null/blank means unknown"
          },
          "botCount": {
            "type": "integer",
            "description": "Number of distinct bots observed from this country"
          },
          "requestCount": {
            "type": "integer",
            "description": "Total bot/crawler requests from this country"
          },
          "previousRequestCount": {
            "type": "integer",
            "description": "Requests from this country in the comparison window. Always present; 0 when no bot reached the site from there.\n"
          },
          "previousBotCount": {
            "type": "integer",
            "description": "Distinct bots observed from this country in the comparison window. Always present.\n"
          },
          "absoluteChange": {
            "type": "integer",
            "description": "requestCount - previousRequestCount. Always present. Requests are the ranked metric, so the change fields describe them rather than the bot count.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Percentage change from previousRequestCount to requestCount. Null when previousRequestCount is 0.\n"
          }
        }
      },
      "PaginatedBotCountryResponse": {
        "type": "object",
        "description": "Paginated per-country bot/crawler breakdown, ordered by request count descending",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BotCountryStat"
            },
            "description": "Per-country stats for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of distinct countries"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "TopBotStat": {
        "type": "object",
        "description": "Bot/crawler traffic aggregated for a single bot, for the top-bots ranking",
        "required": [
          "requestCount"
        ],
        "properties": {
          "botName": {
            "type": "string",
            "nullable": true,
            "description": "Attributed bot name (e.g. GPTBot); null/blank means unknown"
          },
          "vendor": {
            "type": "string",
            "nullable": true,
            "description": "Operating vendor (e.g. OpenAI)"
          },
          "isAi": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether this is an AI crawler/agent"
          },
          "requestCount": {
            "type": "integer",
            "description": "Total bot/crawler requests attributed to this bot"
          },
          "previousRequestCount": {
            "type": "integer",
            "description": "Requests attributed to this bot in the comparison window. Always present; 0 when the bot did not visit at all then, which is how a newly arrived crawler reads.\n"
          },
          "absoluteChange": {
            "type": "integer",
            "description": "requestCount - previousRequestCount. Always present."
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Percentage change from previousRequestCount to requestCount. Null when previousRequestCount is 0.\n"
          }
        }
      },
      "TopBotsResponse": {
        "type": "object",
        "description": "Top bots/crawlers by request count (descending), capped to the requested limit.\n\nThe ranking is always the selected period's. A bot that only appears in the\ncomparison window is absent from this list rather than ranked into it.\n",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TopBotStat"
            },
            "description": "Top bots ordered by request count descending"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "TopPathStat": {
        "type": "object",
        "description": "Bot/crawler traffic aggregated for a single URL path, for the top-scraped-paths ranking",
        "required": [
          "requestCount"
        ],
        "properties": {
          "path": {
            "type": "string",
            "nullable": true,
            "description": "Normalized request path scraped by bots; null/blank means unknown"
          },
          "requestCount": {
            "type": "integer",
            "description": "Total bot/crawler requests observed for this path"
          },
          "vendors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Distinct bot vendors/companies that scraped this path in the range"
          },
          "previousRequestCount": {
            "type": "integer",
            "description": "Requests observed for this path in the comparison window, under the same vendor filter. Always present; 0 when the path was not scraped then.\n"
          },
          "absoluteChange": {
            "type": "integer",
            "description": "requestCount - previousRequestCount. Always present."
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Percentage change from previousRequestCount to requestCount. Null when previousRequestCount is 0.\n"
          }
        }
      },
      "TopPathsResponse": {
        "type": "object",
        "description": "Top paths scraped by bots/crawlers by request count (descending), capped to the\nrequested limit.\n\nThe ranking is always the selected period's. A path scraped only in the\ncomparison window is absent from this list rather than ranked into it.\n",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TopPathStat"
            },
            "description": "Top paths ordered by request count descending"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "SessionDetailResponse": {
        "type": "object",
        "description": "Session detail with metadata",
        "required": [
          "sessionId",
          "startedAt",
          "endedAt",
          "entryPage",
          "exitPage",
          "durationSeconds",
          "isBounce",
          "pageViews",
          "eventsCount"
        ],
        "properties": {
          "sessionId": {
            "type": "string",
            "description": "Unique session identifier"
          },
          "userId": {
            "type": "string",
            "nullable": true,
            "description": "Identified user ID, if available"
          },
          "anonymousId": {
            "type": "string",
            "nullable": true,
            "description": "Anonymous user ID"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the first event in this session"
          },
          "endedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the last event in this session"
          },
          "entryPage": {
            "type": "string",
            "nullable": true,
            "description": "First page visited in this session"
          },
          "exitPage": {
            "type": "string",
            "nullable": true,
            "description": "Last page visited in this session"
          },
          "durationSeconds": {
            "type": "number",
            "format": "double",
            "description": "Total session duration in seconds"
          },
          "isBounce": {
            "type": "boolean",
            "description": "Whether this session had only one screen_view event"
          },
          "referrer": {
            "type": "string",
            "nullable": true,
            "description": "Referrer URL for the session entry"
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country of the user"
          },
          "os": {
            "type": "string",
            "nullable": true,
            "description": "Operating system"
          },
          "browser": {
            "type": "string",
            "nullable": true,
            "description": "Browser name"
          },
          "device": {
            "type": "string",
            "nullable": true,
            "description": "Device type"
          },
          "pageViews": {
            "type": "integer",
            "description": "Number of screen_view events in this session"
          },
          "eventsCount": {
            "type": "integer",
            "description": "Total number of events in this session"
          },
          "sdkVersion": {
            "type": "string",
            "nullable": true,
            "description": "Version of the Kitbase SDK package used during this session"
          }
        }
      },
      "SessionEventResponse": {
        "type": "object",
        "description": "A single event within a session",
        "required": [
          "id",
          "eventName",
          "timestamp"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event identifier"
          },
          "eventName": {
            "type": "string",
            "description": "Name of the event"
          },
          "path": {
            "type": "string",
            "nullable": true,
            "description": "Page path"
          },
          "channel": {
            "type": "string",
            "nullable": true,
            "description": "Event channel"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the event occurred"
          },
          "properties": {
            "type": "object",
            "nullable": true,
            "description": "Event properties (tags) as key-value pairs",
            "additionalProperties": {
              "type": "string"
            }
          },
          "sdkVersion": {
            "type": "string",
            "nullable": true,
            "description": "Version of the Kitbase SDK package that produced this event"
          }
        }
      },
      "PaginatedSessionEventResponse": {
        "type": "object",
        "description": "Paginated list of session events",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionEventResponse"
            },
            "description": "Array of session events for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of events"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "UserAnalyticsSummary": {
        "type": "object",
        "description": "Aggregated user analytics data",
        "required": [
          "resolvedUserId",
          "isIdentified",
          "firstSeen",
          "lastSeen",
          "totalSessions",
          "totalEvents",
          "totalPageViews"
        ],
        "properties": {
          "resolvedUserId": {
            "type": "string",
            "description": "The user_id if identified, otherwise anonymous_id"
          },
          "isIdentified": {
            "type": "boolean",
            "description": "Whether this user has a known user_id"
          },
          "firstSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the first event from this user"
          },
          "lastSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the most recent event from this user"
          },
          "totalSessions": {
            "type": "integer",
            "description": "Number of distinct sessions"
          },
          "totalEvents": {
            "type": "integer",
            "description": "Total number of events"
          },
          "totalPageViews": {
            "type": "integer",
            "description": "Total number of screen_view events"
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country of the user"
          },
          "os": {
            "type": "string",
            "nullable": true,
            "description": "Operating system"
          },
          "browser": {
            "type": "string",
            "nullable": true,
            "description": "Browser name"
          },
          "device": {
            "type": "string",
            "nullable": true,
            "description": "Device type"
          }
        }
      },
      "PaginatedUserAnalyticsResponse": {
        "type": "object",
        "description": "Paginated list of user analytics summaries",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UserAnalyticsSummary"
            },
            "description": "Array of user summaries for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of users"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "AnalyticsUserSummaryResponse": {
        "type": "object",
        "description": "Comprehensive user analytics summary with stats and profile info",
        "required": [
          "userId",
          "isIdentified",
          "totalEvents",
          "sessions",
          "pageViews",
          "avgEventsPerSession",
          "bounceRate",
          "avgSessionDuration",
          "p90SessionDuration",
          "firstSeen",
          "lastSeen",
          "daysActive",
          "conversionEvents",
          "avgTimeBetweenSessions",
          "topEvents",
          "topPages"
        ],
        "properties": {
          "userId": {
            "type": "string",
            "description": "The resolved user ID"
          },
          "isIdentified": {
            "type": "boolean",
            "description": "Whether this user has a known user_id"
          },
          "totalEvents": {
            "type": "integer",
            "description": "Total number of events"
          },
          "sessions": {
            "type": "integer",
            "description": "Number of distinct sessions"
          },
          "pageViews": {
            "type": "integer",
            "description": "Total number of screen_view events"
          },
          "avgEventsPerSession": {
            "type": "number",
            "format": "double",
            "description": "Average events per session"
          },
          "bounceRate": {
            "type": "number",
            "format": "double",
            "description": "Bounce rate as a percentage (0-100)"
          },
          "avgSessionDuration": {
            "type": "number",
            "format": "double",
            "description": "Average session duration in seconds"
          },
          "p90SessionDuration": {
            "type": "number",
            "format": "double",
            "description": "90th percentile session duration in seconds"
          },
          "firstSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the first event from this user"
          },
          "lastSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the most recent event from this user"
          },
          "daysActive": {
            "type": "integer",
            "description": "Number of distinct days with activity"
          },
          "conversionEvents": {
            "type": "integer",
            "description": "Number of non-system events (excludes screen_view, session_start, session_end)"
          },
          "avgTimeBetweenSessions": {
            "type": "number",
            "format": "double",
            "description": "Average time between session starts in seconds"
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country of the user"
          },
          "city": {
            "type": "string",
            "nullable": true,
            "description": "City of the user"
          },
          "os": {
            "type": "string",
            "nullable": true,
            "description": "Operating system"
          },
          "browser": {
            "type": "string",
            "nullable": true,
            "description": "Browser name"
          },
          "device": {
            "type": "string",
            "nullable": true,
            "description": "Device type"
          },
          "topEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnalyticsUserTopItem"
            },
            "description": "Top events by count"
          },
          "topPages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnalyticsUserTopItem"
            },
            "description": "Top pages by visit count"
          }
        }
      },
      "AnalyticsUserTopItem": {
        "type": "object",
        "description": "A top item with name and count",
        "required": [
          "name",
          "count"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Item name (event name or page path)"
          },
          "count": {
            "type": "integer",
            "description": "Number of occurrences"
          }
        }
      },
      "AnalyticsUserActivityDay": {
        "type": "object",
        "description": "Activity data for a single day",
        "required": [
          "date",
          "count"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "The date (YYYY-MM-DD)"
          },
          "count": {
            "type": "integer",
            "description": "Number of events on this day"
          }
        }
      },
      "AnalyticsUserActivityResponse": {
        "type": "object",
        "description": "User activity heatmap data",
        "required": [
          "days"
        ],
        "properties": {
          "days": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnalyticsUserActivityDay"
            },
            "description": "Array of daily activity counts"
          }
        }
      },
      "AnalyticsUserEventResponse": {
        "type": "object",
        "description": "A single event in a user's timeline",
        "required": [
          "id",
          "eventName",
          "timestamp"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event identifier"
          },
          "eventName": {
            "type": "string",
            "description": "Name of the event"
          },
          "path": {
            "type": "string",
            "nullable": true,
            "description": "Page path"
          },
          "channel": {
            "type": "string",
            "nullable": true,
            "description": "Event channel"
          },
          "country": {
            "type": "string",
            "nullable": true,
            "description": "Country"
          },
          "os": {
            "type": "string",
            "nullable": true,
            "description": "Operating system"
          },
          "browser": {
            "type": "string",
            "nullable": true,
            "description": "Browser name"
          },
          "userId": {
            "type": "string",
            "nullable": true,
            "description": "Identified user ID"
          },
          "anonymousId": {
            "type": "string",
            "nullable": true,
            "description": "Anonymous user ID"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "When the event occurred"
          }
        }
      },
      "PaginatedAnalyticsUserEventResponse": {
        "type": "object",
        "description": "Paginated list of user events",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AnalyticsUserEventResponse"
            },
            "description": "Array of events for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of events"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "EventUserSummary": {
        "type": "object",
        "description": "Summary of a user's event activity",
        "required": [
          "userId",
          "firstSeen",
          "lastSeen",
          "eventCount"
        ],
        "properties": {
          "userId": {
            "type": "string",
            "description": "User identifier"
          },
          "firstSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of first event from this user"
          },
          "lastSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of most recent event from this user"
          },
          "eventCount": {
            "type": "integer",
            "description": "Total number of events from this user"
          }
        }
      },
      "PaginatedEventUsersResponse": {
        "type": "object",
        "description": "Paginated list of event users",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventUserSummary"
            },
            "description": "Array of users for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of unique users"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "EventUserTopEvent": {
        "type": "object",
        "description": "A top event for a user",
        "required": [
          "eventName",
          "count",
          "percentage"
        ],
        "properties": {
          "eventName": {
            "type": "string",
            "description": "Name of the event"
          },
          "count": {
            "type": "integer",
            "description": "Number of times this event occurred"
          },
          "percentage": {
            "type": "number",
            "format": "double",
            "description": "Percentage of user's total events"
          }
        }
      },
      "EventUserDetailsResponse": {
        "type": "object",
        "description": "Detailed user event information",
        "required": [
          "userId",
          "firstSeen",
          "lastSeen",
          "totalEventCount",
          "topEvents"
        ],
        "properties": {
          "userId": {
            "type": "string",
            "description": "User identifier"
          },
          "firstSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of first event from this user"
          },
          "lastSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of most recent event from this user"
          },
          "totalEventCount": {
            "type": "integer",
            "description": "Total number of events from this user"
          },
          "topEvents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventUserTopEvent"
            },
            "description": "Top 10 most frequent events from this user"
          }
        }
      },
      "EventStatsGroup": {
        "type": "object",
        "description": "A single group in event statistics",
        "required": [
          "key",
          "count",
          "percentage"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "Group key (event name, environment, channel, etc.)"
          },
          "count": {
            "type": "integer",
            "description": "Number of events in this group"
          },
          "percentage": {
            "type": "number",
            "format": "double",
            "description": "Percentage of total events"
          }
        }
      },
      "EventStatsResponse": {
        "type": "object",
        "description": "Aggregated event statistics",
        "required": [
          "totalEvents",
          "uniqueUsers",
          "groups"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time",
            "description": "Start of the time range"
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "description": "End of the time range"
          },
          "totalEvents": {
            "type": "integer",
            "description": "Total number of events in range"
          },
          "uniqueUsers": {
            "type": "integer",
            "description": "Number of unique users"
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventStatsGroup"
            },
            "description": "Grouped event counts"
          }
        }
      },
      "EventTimelinePoint": {
        "type": "object",
        "description": "A single data point in the timeline",
        "required": [
          "timestamp",
          "count"
        ],
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Time bucket start"
          },
          "count": {
            "type": "integer",
            "description": "Number of events in this bucket"
          }
        }
      },
      "EventTimelineResponse": {
        "type": "object",
        "description": "Event counts over time for charts",
        "required": [
          "interval",
          "data"
        ],
        "properties": {
          "interval": {
            "type": "string",
            "description": "Time interval (hour, day, week, month)",
            "enum": [
              "hour",
              "day",
              "week",
              "month"
            ]
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventTimelinePoint"
            },
            "description": "Timeline data points"
          }
        }
      },
      "EventAggregation": {
        "type": "object",
        "description": "Aggregated metrics for a single unique event name over the selected time range",
        "required": [
          "eventName",
          "count",
          "uniqueUsers",
          "firstSeen",
          "lastSeen",
          "last24hSparkline"
        ],
        "properties": {
          "eventName": {
            "type": "string",
            "description": "The event name"
          },
          "count": {
            "type": "integer",
            "format": "int64",
            "description": "Total number of events in the selected time range"
          },
          "uniqueUsers": {
            "type": "integer",
            "description": "Number of unique users that triggered this event in the selected time range"
          },
          "firstSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the first occurrence in the selected time range"
          },
          "lastSeen": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp of the most recent occurrence in the selected time range"
          },
          "last24hSparkline": {
            "type": "array",
            "description": "24 hourly event counts for the last 24 hours (oldest bucket first), independent\nof the selected time range. Missing hours are filled with 0 so the frontend can\nrender a fixed-width bar sparkline.\n",
            "items": {
              "type": "integer"
            }
          }
        }
      },
      "PaginatedEventAggregations": {
        "type": "object",
        "description": "Paginated list of aggregated unique events",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventAggregation"
            },
            "description": "Array of aggregated events for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number (0-indexed)"
          },
          "size": {
            "type": "integer",
            "description": "Items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of distinct event names"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "FlexibleTimelinePoint": {
        "type": "object",
        "description": "A single data point in a flexible timeline series",
        "required": [
          "datetime",
          "count"
        ],
        "properties": {
          "datetime": {
            "type": "string",
            "format": "date-time",
            "description": "The truncated datetime of the bucket (ISO 8601)"
          },
          "count": {
            "type": "integer",
            "description": "The number of events in this bucket"
          }
        }
      },
      "FlexibleWebTimelinePeriod": {
        "type": "object",
        "description": "Web analytics timeline data for a single period using flexible granularity",
        "required": [
          "pageviews",
          "sessions",
          "uniqueVisitors"
        ],
        "properties": {
          "pageviews": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlexibleTimelinePoint"
            },
            "description": "Pageview counts per time bucket"
          },
          "sessions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlexibleTimelinePoint"
            },
            "description": "Session counts per time bucket"
          },
          "uniqueVisitors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlexibleTimelinePoint"
            },
            "description": "Unique visitor counts per time bucket"
          }
        }
      },
      "FlexibleWebTimelineResponse": {
        "type": "object",
        "description": "Web analytics timeline data with flexible granularity for current and previous periods",
        "required": [
          "currentPeriod",
          "previousPeriod",
          "granularity"
        ],
        "properties": {
          "currentPeriod": {
            "$ref": "#/components/schemas/FlexibleWebTimelinePeriod"
          },
          "previousPeriod": {
            "$ref": "#/components/schemas/FlexibleWebTimelinePeriod"
          },
          "granularity": {
            "$ref": "#/components/schemas/TimelineInterval"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "ActivityHeatmapRowDimension": {
        "type": "string",
        "description": "What the rows of the visitor activity heatmap are grouped by",
        "enum": [
          "day_of_week",
          "country"
        ]
      },
      "ActivityHeatmapCell": {
        "type": "object",
        "description": "Unique visitors in one hour-of-day bucket of a heatmap row",
        "required": [
          "hour",
          "visitors"
        ],
        "properties": {
          "hour": {
            "type": "integer",
            "minimum": 0,
            "maximum": 23,
            "description": "Hour of the day (0-23) in the project's reporting timezone"
          },
          "visitors": {
            "type": "integer",
            "description": "Distinct visitors whose session started in this hour bucket"
          }
        }
      },
      "ActivityHeatmapRow": {
        "type": "object",
        "description": "One row of the heatmap, always carrying all 24 hourly cells so the grid is complete.\n",
        "required": [
          "key",
          "cells"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "Row identity, interpreted per the response's rowDimension:\nthe ISO day number as a string (\"1\" = Monday … \"7\" = Sunday) for day_of_week,\nor the country value (ISO alpha-2 code, or \"Unknown\") for country.\n"
          },
          "cells": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityHeatmapCell"
            },
            "description": "The 24 hourly cells, ordered by hour ascending"
          }
        }
      },
      "WebAnalyticsActivityHeatmapResponse": {
        "type": "object",
        "description": "Distinct visitors per (row, hour-of-day) cell, for the \"when do people visit\" heatmap.\n\nCells count distinct visitors within their own bucket and therefore do not sum to the\nperiod total — the same person browsing on Monday and Tuesday counts in both rows.\nOver windows longer than a week a day_of_week cell aggregates every occurrence of that\nweekday in the window, so weekdays that occur one extra time read slightly higher.\n",
        "required": [
          "rowDimension",
          "from",
          "to",
          "rows"
        ],
        "properties": {
          "rowDimension": {
            "$ref": "#/components/schemas/ActivityHeatmapRowDimension"
          },
          "from": {
            "type": "string",
            "format": "date",
            "description": "First day actually queried, in the project's reporting timezone. The heatmap needs at least a\nweek of days to be readable, so a narrower selected range is widened to the last\n7 days; wider ranges are used as selected. Echoed so the UI can label the window.\n"
          },
          "to": {
            "type": "string",
            "format": "date",
            "description": "Last day actually queried (inclusive), in the project's reporting timezone"
          },
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityHeatmapRow"
            },
            "description": "All 7 weekdays (Monday first) for day_of_week, or the busiest countries ordered by\ntotal visitors descending for country.\n"
          }
        }
      },
      "BotVendorTimelineResponse": {
        "type": "object",
        "description": "Bot/crawler request counts over time, grouped by vendor, for per-vendor bar charts.",
        "required": [
          "interval",
          "series"
        ],
        "properties": {
          "interval": {
            "$ref": "#/components/schemas/TimelineInterval"
          },
          "series": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BotVendorTimelineSeries"
            },
            "description": "One series per vendor, ordered by total descending."
          },
          "comparisonSeries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BotVendorTimelineSeries"
            },
            "description": "The same per-vendor series read over the comparison window, at the same interval\nand ordered the same way. Always present.\n\nIts buckets carry the comparison window's own datetimes, so a chart lines\nthe two up by position rather than by date. A vendor that only crawled in\nthe comparison window has a series here and none in `series`, and one that\nonly crawled in the selected period has the reverse.\n"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "BotVendorTimelineSeries": {
        "type": "object",
        "description": "Time-bucketed bot/crawler counts for a single vendor.",
        "required": [
          "vendor",
          "total",
          "data"
        ],
        "properties": {
          "vendor": {
            "type": "string",
            "description": "Bot vendor/provider name (e.g. OpenAI, Google, Bing). \"Unknown\" when the vendor could not be attributed."
          },
          "total": {
            "type": "integer",
            "description": "Total bot requests for this vendor across the selected period."
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlexibleTimelinePoint"
            },
            "description": "Per-bucket counts for this vendor (datetime + count), ordered chronologically."
          }
        }
      },
      "TimelineInterval": {
        "type": "string",
        "description": "Time-bucketing granularity for timeline data",
        "enum": [
          "minute",
          "hour",
          "day"
        ]
      },
      "FunnelAnalysisMode": {
        "type": "string",
        "description": "Funnel analysis grouping mode:\n- session: steps must occur within the same session (all visitors)\n- user: steps can span multiple sessions (identified users only, requires user_id)\n",
        "enum": [
          "session",
          "user"
        ]
      },
      "FunnelStepType": {
        "type": "string",
        "description": "Type of funnel step",
        "enum": [
          "page",
          "event"
        ]
      },
      "StepFilterOperator": {
        "type": "string",
        "description": "Operator for step filter matching",
        "enum": [
          "is",
          "is_not"
        ]
      },
      "StepFilter": {
        "type": "object",
        "description": "A dimension-based filter for funnel step matching",
        "required": [
          "dimension",
          "operator",
          "values"
        ],
        "properties": {
          "dimension": {
            "type": "string",
            "description": "A BreakdownDimension value (e.g. \"country\", \"browser\") or a custom event property key (e.g. \"plan_type\")"
          },
          "operator": {
            "$ref": "#/components/schemas/StepFilterOperator"
          },
          "values": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Values to match against"
          }
        }
      },
      "FunnelStep": {
        "type": "object",
        "description": "A single step in a funnel definition",
        "required": [
          "type",
          "value"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/FunnelStepType"
          },
          "value": {
            "type": "string",
            "description": "Path pattern (e.g. \"/pricing\", \"/blog/*\") for page steps, or event name (e.g. \"signup_complete\") for event steps"
          },
          "name": {
            "type": "string",
            "description": "Optional display label for the step"
          },
          "filters": {
            "type": "array",
            "description": "Optional dimension-based filters for the step",
            "items": {
              "$ref": "#/components/schemas/StepFilter"
            }
          }
        }
      },
      "CreateFunnelRequest": {
        "type": "object",
        "description": "Request body to create a new funnel",
        "required": [
          "name",
          "steps"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Funnel display name"
          },
          "analysisMode": {
            "$ref": "#/components/schemas/FunnelAnalysisMode",
            "description": "Analysis grouping mode (defaults to session)",
            "default": "session"
          },
          "steps": {
            "type": "array",
            "minItems": 2,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/FunnelStep"
            },
            "description": "Ordered list of funnel steps (2-10)"
          }
        }
      },
      "UpdateFunnelRequest": {
        "type": "object",
        "description": "Request body to update an existing funnel",
        "required": [
          "name",
          "steps"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Funnel display name"
          },
          "analysisMode": {
            "$ref": "#/components/schemas/FunnelAnalysisMode",
            "description": "Analysis grouping mode (defaults to session)",
            "default": "session"
          },
          "steps": {
            "type": "array",
            "minItems": 2,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/FunnelStep"
            },
            "description": "Ordered list of funnel steps (2-10)"
          }
        }
      },
      "AnalyzeFunnelRequest": {
        "type": "object",
        "description": "Request body to run funnel analysis (ad-hoc or for a saved funnel)",
        "required": [
          "steps"
        ],
        "properties": {
          "analysisMode": {
            "$ref": "#/components/schemas/FunnelAnalysisMode",
            "description": "Analysis grouping mode (defaults to session)",
            "default": "session"
          },
          "steps": {
            "type": "array",
            "minItems": 2,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/FunnelStep"
            },
            "description": "Ordered list of funnel steps (2-10)"
          }
        }
      },
      "SavedFunnel": {
        "type": "object",
        "description": "A saved funnel definition",
        "required": [
          "id",
          "name",
          "analysisMode",
          "steps",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique funnel identifier"
          },
          "name": {
            "type": "string",
            "description": "Funnel display name"
          },
          "analysisMode": {
            "$ref": "#/components/schemas/FunnelAnalysisMode"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelStep"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FunnelStepResult": {
        "type": "object",
        "description": "Analysis result for a single funnel step",
        "required": [
          "stepNumber",
          "stepName",
          "count",
          "conversionRate",
          "dropoffRate"
        ],
        "properties": {
          "stepNumber": {
            "type": "integer",
            "description": "1-based step position in the funnel"
          },
          "stepName": {
            "type": "string",
            "description": "Display name for the step"
          },
          "count": {
            "type": "integer",
            "description": "Number of unique sessions (session mode) or users (user mode) that reached this step"
          },
          "conversionRate": {
            "type": "number",
            "format": "double",
            "description": "Percentage of step 1 entities that reached this step (0-100)"
          },
          "dropoffRate": {
            "type": "number",
            "format": "double",
            "description": "Percentage that dropped off from the previous step (0-100). Step 1 is always 0."
          }
        }
      },
      "FunnelAnalysisResponse": {
        "type": "object",
        "description": "Complete funnel analysis result",
        "required": [
          "steps",
          "analysisMode",
          "from",
          "to"
        ],
        "properties": {
          "analysisMode": {
            "$ref": "#/components/schemas/FunnelAnalysisMode"
          },
          "from": {
            "type": "string",
            "format": "date",
            "description": "First day the analysis covers, in the project's reporting timezone. Echoed\nbecause the window is resolved on the server — `last_7_days` is today plus the\nsix days before it — so a caller labels the period it actually got, not the one\nit believes it asked for.\n"
          },
          "to": {
            "type": "string",
            "format": "date",
            "description": "Last day the analysis covers (inclusive), in the project's reporting timezone."
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelStepResult"
            }
          }
        }
      },
      "FunnelSessionSummary": {
        "type": "object",
        "description": "Summary of a session that reached or dropped at a funnel step",
        "properties": {
          "sessionId": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "anonymousId": {
            "type": "string"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "durationSeconds": {
            "type": "number",
            "format": "double"
          },
          "entryPage": {
            "type": "string"
          },
          "exitPage": {
            "type": "string"
          },
          "pageViews": {
            "type": "integer"
          },
          "eventsCount": {
            "type": "integer"
          },
          "country": {
            "type": "string"
          },
          "browser": {
            "type": "string"
          },
          "os": {
            "type": "string"
          },
          "device": {
            "type": "string"
          },
          "utmSource": {
            "type": "string"
          },
          "utmMedium": {
            "type": "string"
          },
          "utmCampaign": {
            "type": "string"
          }
        }
      },
      "PaginatedFunnelSessionResponse": {
        "type": "object",
        "description": "Paginated list of sessions for a funnel step drill-down",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelSessionSummary"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "AnalyzeJourneyRequest": {
        "type": "object",
        "description": "Request body to run journey analysis on screen_view events",
        "properties": {
          "steps": {
            "type": "integer",
            "minimum": 2,
            "maximum": 10,
            "default": 3,
            "description": "Maximum number of steps per journey path"
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 500,
            "default": 100,
            "description": "Maximum number of journey paths to return"
          },
          "stepFilters": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Optional step index to path pattern filters (e.g. {\"0\": \"/pricing\", \"2\": \"/checkout/*\"}). Keys are 0-based step indices."
          }
        }
      },
      "JourneyPath": {
        "type": "object",
        "description": "A single journey path with session count and percentage",
        "required": [
          "path",
          "count",
          "percentage"
        ],
        "properties": {
          "path": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ordered page paths in the journey"
          },
          "count": {
            "type": "integer",
            "description": "Number of sessions that followed this path"
          },
          "percentage": {
            "type": "number",
            "format": "double",
            "description": "Percentage of total sessions that followed this path"
          }
        }
      },
      "JourneyAnalysisResponse": {
        "type": "object",
        "description": "Complete journey analysis result with paths and session counts",
        "required": [
          "journeys",
          "totalSessions"
        ],
        "properties": {
          "journeys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/JourneyPath"
            },
            "description": "Journey paths ordered by session count descending"
          },
          "totalSessions": {
            "type": "integer",
            "description": "Total number of sessions with screen_view events in the analysis period"
          }
        }
      },
      "DateRangePreset": {
        "type": "string",
        "description": "Predefined date range preset for analytics queries",
        "enum": [
          "last_30_minutes",
          "last_hour",
          "today",
          "yesterday",
          "last_7_days",
          "last_30_days",
          "this_month",
          "this_year"
        ]
      },
      "ComparisonPreset": {
        "type": "string",
        "description": "Which earlier window a report's comparison figures are read from. Every window\nis resolved in the project's reporting timezone.\n\n- `previous_period`: keeps the length of the selected period and ends immediately\n  before it starts, so the two windows never overlap.\n- `previous_week` / `previous_month` / `previous_quarter` / `previous_year`: both\n  ends of the selected period are moved back by 7 days, or by 1, 3 or 12 calendar\n  months, clamped to the shorter month (a boundary on May 31 moves to April 30).\n\nThe calendar presets therefore preserve calendar alignment rather than duration:\nall of July compares against all of June, 31 days against 30. A selection of\nexactly one calendar week, month, quarter or year maps onto the previous one\nexactly. A selection **longer** than the shift distance still overlaps the current\nperiod — three months compared against `previous_month` share two of them — which\nis what \"one month earlier\" means, and the only case where the windows overlap.\n\nA comparison window may not start more than 1 year before the selected period.\n",
        "enum": [
          "previous_period",
          "previous_week",
          "previous_month",
          "previous_quarter",
          "previous_year"
        ],
        "x-enum-varnames": [
          "PREVIOUS_PERIOD",
          "PREVIOUS_WEEK",
          "PREVIOUS_MONTH",
          "PREVIOUS_QUARTER",
          "PREVIOUS_YEAR"
        ]
      },
      "ComparisonWindow": {
        "type": "object",
        "description": "The window the comparison figures were read from, echoed so a report can\nlabel what it compares against. Present on every report that reads a date\nrange — which is all of them except an AI visibility read answering by job\ncount, where there is no period to have compared with.\n",
        "required": [
          "from",
          "to"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time",
            "description": "First instant of the comparison window, inclusive (UTC)."
          },
          "to": {
            "type": "string",
            "format": "date-time",
            "description": "End of the comparison window, exclusive (UTC)."
          }
        }
      },
      "MetricValue": {
        "type": "object",
        "description": "A metric value with current vs previous comparison",
        "required": [
          "current",
          "previous",
          "change"
        ],
        "properties": {
          "current": {
            "type": "number",
            "description": "Current period value"
          },
          "previous": {
            "type": "number",
            "nullable": true,
            "description": "The same metric over the comparison window. Null — never 0 — when that window holds nothing to measure: a rate needs sessions to be a rate, and reporting 0% bounce for an hour nobody visited would invent a measurement and then invent a change from it.\n"
          },
          "change": {
            "type": "number",
            "nullable": true,
            "description": "Relative change from previous to current, as a percentage to one decimal. Null when previous is 0 or absent — there is no percentage that describes a rise from nothing, and reporting one (this field used to answer 100) turned an empty comparison window into a doubling.\n",
            "format": "double"
          }
        }
      },
      "WebAnalyticsResponse": {
        "type": "object",
        "description": "Web analytics metrics (OpenPanel-style)",
        "required": [
          "uniqueVisitors",
          "sessions",
          "pageviews",
          "pagesPerSession",
          "bounceRate",
          "avgSessionDuration",
          "revenue"
        ],
        "properties": {
          "uniqueVisitors": {
            "$ref": "#/components/schemas/MetricValue"
          },
          "sessions": {
            "$ref": "#/components/schemas/MetricValue"
          },
          "pageviews": {
            "$ref": "#/components/schemas/MetricValue"
          },
          "pagesPerSession": {
            "$ref": "#/components/schemas/MetricValue"
          },
          "bounceRate": {
            "$ref": "#/components/schemas/MetricValue"
          },
          "avgSessionDuration": {
            "$ref": "#/components/schemas/MetricValue"
          },
          "revenue": {
            "$ref": "#/components/schemas/MetricValue"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "DimensionMetric": {
        "type": "object",
        "description": "A metric for a single dimension value (e.g., a browser, country, etc.)",
        "required": [
          "name",
          "count"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "The dimension value (e.g., \"Chrome\", \"US\", \"Mobile\")"
          },
          "count": {
            "type": "integer",
            "description": "Number of events/sessions for this value"
          },
          "visitors": {
            "type": "integer",
            "description": "Number of unique visitors (only present for top_page dimension)"
          },
          "views": {
            "type": "integer",
            "description": "Total page views (only present for top_page dimension)"
          },
          "previousCount": {
            "type": "integer",
            "description": "Count for the same dimension value in the comparison window. Always present; 0 when the value has no rows there.\n"
          },
          "previousVisitors": {
            "type": "integer",
            "description": "Unique visitors in the comparison window (only present for the top_page dimension, and only when a comparison was requested).\n"
          },
          "previousViews": {
            "type": "integer",
            "description": "Page views in the comparison window (only present for the top_page dimension, and only when a comparison was requested).\n"
          },
          "absoluteChange": {
            "type": "integer",
            "description": "count - previousCount. Always present."
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Percentage change from previousCount to count. Null when previousCount is 0.\n"
          }
        }
      },
      "PaginatedBreakdownResponse": {
        "type": "object",
        "description": "Paginated breakdown analytics response for any dimension",
        "required": [
          "dimension",
          "data",
          "total",
          "page",
          "pageSize",
          "totalItems"
        ],
        "properties": {
          "dimension": {
            "type": "string",
            "description": "The dimension that was queried",
            "example": "country"
          },
          "data": {
            "type": "array",
            "description": "Breakdown data for the dimension",
            "items": {
              "$ref": "#/components/schemas/DimensionMetric"
            }
          },
          "total": {
            "type": "integer",
            "description": "Total count across all values"
          },
          "page": {
            "type": "integer",
            "description": "Current page number (0-indexed)"
          },
          "pageSize": {
            "type": "integer",
            "description": "Number of items per page"
          },
          "totalItems": {
            "type": "integer",
            "description": "Total number of distinct dimension values"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "PageDurationMetric": {
        "type": "object",
        "description": "A metric showing average time spent on a page",
        "required": [
          "name",
          "avgDurationMs",
          "visitCount",
          "percentage"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "The page path",
            "example": "/dashboard"
          },
          "avgDurationMs": {
            "type": "number",
            "format": "double",
            "description": "Average time spent on the page in milliseconds",
            "example": 45200
          },
          "visitCount": {
            "type": "integer",
            "description": "Number of visits to this page",
            "example": 1250
          },
          "percentage": {
            "type": "number",
            "format": "double",
            "description": "Percentage of total time spent across all pages",
            "example": 15.5
          },
          "previousAvgDurationMs": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Average time spent on the page in the comparison window. Null when no comparison was requested, and null — not 0 — when the page was never visited in the comparison window, because \"nobody read it\" is not a duration of zero.\n"
          },
          "absoluteChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "avgDurationMs - previousAvgDurationMs, in milliseconds. Null when there is no comparison figure to subtract.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Percentage change from previousAvgDurationMs to avgDurationMs. Null when there is no comparison figure, or when it is 0.\n"
          }
        }
      },
      "PageDurationBreakdownResponse": {
        "type": "object",
        "description": "Response containing top pages by average time spent",
        "required": [
          "data",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "description": "List of pages with duration metrics, ordered by avgDurationMs descending",
            "items": {
              "$ref": "#/components/schemas/PageDurationMetric"
            }
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of unique pages in the period"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "DimensionTimelineDataPoint": {
        "type": "object",
        "description": "A single data point in a dimension timeline",
        "required": [
          "date",
          "count"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "The date (YYYY-MM-DD)"
          },
          "count": {
            "type": "integer",
            "description": "The count for this date"
          }
        }
      },
      "DimensionTimelineResponse": {
        "type": "object",
        "description": "Timeline data for a specific dimension value",
        "required": [
          "dimension",
          "value",
          "data"
        ],
        "properties": {
          "dimension": {
            "type": "string",
            "description": "The dimension type (browser, country, device, etc.)"
          },
          "value": {
            "type": "string",
            "description": "The dimension value being drilled down"
          },
          "data": {
            "type": "array",
            "description": "Timeline data points",
            "items": {
              "$ref": "#/components/schemas/DimensionTimelineDataPoint"
            }
          },
          "comparisonData": {
            "type": "array",
            "description": "The same series read over the comparison window, bucketed by day. Always present. Its dates are the comparison window's own, so a chart plots it against the current series by position rather than by date.\n",
            "items": {
              "$ref": "#/components/schemas/DimensionTimelineDataPoint"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "UniqueValuesResponse": {
        "type": "object",
        "description": "Response containing a list of unique string values",
        "required": [
          "values"
        ],
        "properties": {
          "values": {
            "type": "array",
            "description": "List of unique values",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "FeatureFlagValueTypeEnum": {
        "type": "string",
        "enum": [
          "boolean",
          "string",
          "number",
          "json"
        ],
        "description": "The data type of the feature flag value"
      },
      "FeatureFlagOperatorEnum": {
        "type": "string",
        "enum": [
          "eq",
          "neq",
          "contains",
          "not_contains",
          "starts_with",
          "ends_with",
          "gt",
          "gte",
          "lt",
          "lte",
          "exists",
          "not_exists",
          "in",
          "not_in"
        ],
        "description": "Operator for segment rule conditions"
      },
      "CreateFeatureFlagRequest": {
        "type": "object",
        "description": "Request to create a new feature flag",
        "required": [
          "flagKey",
          "name",
          "valueType"
        ],
        "properties": {
          "flagKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$",
            "description": "Unique key for the flag within the project (alphanumeric, underscores, hyphens)"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Human-readable name for the flag"
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "description": "Description of what this flag controls"
          },
          "valueType": {
            "$ref": "#/components/schemas/FeatureFlagValueTypeEnum"
          },
          "defaultEnabled": {
            "type": "boolean",
            "default": false,
            "description": "Default enabled state for this environment"
          },
          "defaultValue": {
            "description": "Default value when flag is enabled (type depends on valueType)"
          },
          "rules": {
            "type": "array",
            "description": "Optional targeting rules to create with the flag",
            "items": {
              "$ref": "#/components/schemas/FeatureFlagRuleRequest"
            }
          }
        }
      },
      "UpdateFeatureFlagRequest": {
        "type": "object",
        "description": "Request to update a feature flag. The default value can be updated even when the flag is disabled.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Human-readable name for the flag"
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "description": "Description of what this flag controls"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the flag is enabled in this environment"
          },
          "value": {
            "description": "Default value for the flag (type depends on valueType). Can be updated even when the flag is disabled. Deprecated: use defaultValue instead."
          },
          "defaultValue": {
            "description": "Default value for the flag (type depends on valueType). Can be updated even when the flag is disabled."
          },
          "rules": {
            "type": "array",
            "description": "Optional targeting rules. When provided, replaces all existing rules.",
            "items": {
              "$ref": "#/components/schemas/FeatureFlagRuleRequest"
            }
          }
        }
      },
      "CreateFeatureFlagSegmentRequest": {
        "type": "object",
        "description": "Request to create a new targeting segment",
        "required": [
          "name",
          "rules"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Name of the segment"
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "description": "Description of this segment"
          },
          "rules": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/FeatureFlagSegmentRuleRequest"
            },
            "description": "List of rules that define this segment"
          }
        }
      },
      "UpdateFeatureFlagSegmentRequest": {
        "type": "object",
        "description": "Request to update a targeting segment",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Name of the segment"
          },
          "description": {
            "type": "string",
            "maxLength": 1000,
            "description": "Description of this segment"
          },
          "rules": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/FeatureFlagSegmentRuleRequest"
            },
            "description": "List of rules that define this segment"
          }
        }
      },
      "FeatureFlagSegmentRuleRequest": {
        "type": "object",
        "description": "A single rule condition for a segment",
        "required": [
          "field",
          "operator"
        ],
        "properties": {
          "field": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "The trait/attribute field to match against"
          },
          "operator": {
            "$ref": "#/components/schemas/FeatureFlagOperatorEnum"
          },
          "value": {
            "type": "string",
            "description": "The value to compare against (not required for exists/not_exists operators)"
          }
        }
      },
      "FeatureFlagRuleRequest": {
        "type": "object",
        "description": "A targeting rule for a feature flag",
        "required": [
          "enabled"
        ],
        "properties": {
          "segmentId": {
            "type": "string",
            "description": "ID of the segment to match (optional - if not provided, rule applies to all)"
          },
          "rolloutPercentage": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Percentage of matching identities to enable for (0-100)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether to enable the flag when this rule matches"
          },
          "value": {
            "description": "Value to return when this rule matches (type depends on flag valueType)"
          }
        }
      },
      "OpenFeatureReasonEnum": {
        "type": "string",
        "enum": [
          "STATIC",
          "DEFAULT",
          "TARGETING_MATCH",
          "SPLIT",
          "CACHED",
          "DISABLED",
          "UNKNOWN",
          "STALE",
          "ERROR"
        ],
        "description": "OpenFeature-compatible reason for the resolved value:\n- STATIC: Flag resolved to its default value (no targeting rules matched)\n- DEFAULT: Client-provided default was returned (flag not found or error)\n- TARGETING_MATCH: Flag resolved based on targeting rules\n- SPLIT: Flag resolved based on percentage rollout\n- CACHED: Value was from cache\n- DISABLED: Flag is disabled\n- UNKNOWN: Reason is unknown\n- STALE: Cached value that may be outdated\n- ERROR: An error occurred during evaluation\n"
      },
      "OpenFeatureErrorCodeEnum": {
        "type": "string",
        "enum": [
          "PROVIDER_NOT_READY",
          "FLAG_NOT_FOUND",
          "PARSE_ERROR",
          "TYPE_MISMATCH",
          "TARGETING_KEY_MISSING",
          "INVALID_CONTEXT",
          "GENERAL"
        ],
        "description": "OpenFeature-compatible error codes:\n- PROVIDER_NOT_READY: Provider is not ready\n- FLAG_NOT_FOUND: Flag does not exist\n- PARSE_ERROR: Error parsing flag configuration\n- TYPE_MISMATCH: Requested type doesn't match flag type\n- TARGETING_KEY_MISSING: Required targeting key is missing\n- INVALID_CONTEXT: Evaluation context is invalid\n- GENERAL: General error\n"
      },
      "FeatureFlagSnapshotRequest": {
        "type": "object",
        "description": "Request to evaluate feature flags for a specific identity (OpenFeature compatible)",
        "properties": {
          "identityId": {
            "type": "string",
            "maxLength": 255,
            "description": "Unique identifier for the user/device (used for percentage rollouts). Maps to OpenFeature targetingKey."
          },
          "context": {
            "type": "object",
            "additionalProperties": true,
            "description": "Evaluation context with typed values (OpenFeature compatible). Supports string, number, boolean, and nested objects."
          }
        }
      },
      "EvaluateFlagRequest": {
        "type": "object",
        "description": "Request to evaluate a single feature flag (OpenFeature compatible)",
        "required": [
          "flagKey"
        ],
        "properties": {
          "flagKey": {
            "type": "string",
            "description": "The key of the flag to evaluate"
          },
          "identityId": {
            "type": "string",
            "maxLength": 255,
            "description": "Unique identifier for the user/device (used for percentage rollouts). Maps to OpenFeature targetingKey."
          },
          "context": {
            "type": "object",
            "additionalProperties": true,
            "description": "Evaluation context with typed values (OpenFeature compatible)"
          },
          "defaultValue": {
            "description": "Default value to return if flag cannot be evaluated (type should match flag type)"
          }
        }
      },
      "FeatureFlagResponse": {
        "type": "object",
        "description": "Feature flag information",
        "required": [
          "id",
          "flagKey",
          "name",
          "valueType",
          "enabled",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the feature flag"
          },
          "flagKey": {
            "type": "string",
            "description": "Unique key for the flag within the project"
          },
          "name": {
            "type": "string",
            "description": "Human-readable name for the flag"
          },
          "description": {
            "type": "string",
            "description": "Description of what this flag controls"
          },
          "valueType": {
            "$ref": "#/components/schemas/FeatureFlagValueTypeEnum"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the flag is enabled in this environment"
          },
          "value": {
            "description": "Current value in this environment (type depends on valueType)"
          },
          "createdBy": {
            "type": "string",
            "description": "User ID who created the flag"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the flag was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the flag was last updated"
          }
        }
      },
      "FeatureFlagDetailResponse": {
        "type": "object",
        "description": "Detailed feature flag information including rules",
        "required": [
          "id",
          "flagKey",
          "name",
          "valueType",
          "enabled",
          "rules",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the feature flag"
          },
          "flagKey": {
            "type": "string",
            "description": "Unique key for the flag within the project"
          },
          "name": {
            "type": "string",
            "description": "Human-readable name for the flag"
          },
          "description": {
            "type": "string",
            "description": "Description of what this flag controls"
          },
          "valueType": {
            "$ref": "#/components/schemas/FeatureFlagValueTypeEnum"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the flag is enabled in this environment"
          },
          "value": {
            "description": "Default value in this environment (type depends on valueType)"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureFlagRuleResponse"
            },
            "description": "Ordered list of targeting rules"
          },
          "createdBy": {
            "type": "string",
            "description": "User ID who created the flag"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the flag was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the flag was last updated"
          }
        }
      },
      "FeatureFlagRuleResponse": {
        "type": "object",
        "description": "A targeting rule for a feature flag",
        "required": [
          "id",
          "priority",
          "enabled"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the rule"
          },
          "priority": {
            "type": "integer",
            "description": "Order of evaluation (lower = higher priority)"
          },
          "segment": {
            "$ref": "#/components/schemas/FeatureFlagSegmentSummaryResponse"
          },
          "rolloutPercentage": {
            "type": "number",
            "description": "Percentage of matching identities to enable for"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether to enable the flag when this rule matches"
          },
          "value": {
            "description": "Value to return when this rule matches"
          }
        }
      },
      "FeatureFlagSegmentResponse": {
        "type": "object",
        "description": "Feature flag targeting segment",
        "required": [
          "id",
          "name",
          "rules",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the segment"
          },
          "name": {
            "type": "string",
            "description": "Name of the segment"
          },
          "description": {
            "type": "string",
            "description": "Description of this segment"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureFlagSegmentRuleResponse"
            },
            "description": "List of rules that define this segment"
          },
          "createdBy": {
            "type": "string",
            "description": "User ID who created the segment"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the segment was created"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the segment was last updated"
          }
        }
      },
      "FeatureFlagSegmentSummaryResponse": {
        "type": "object",
        "description": "Summary of a feature flag segment (for embedding in rules)",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the segment"
          },
          "name": {
            "type": "string",
            "description": "Name of the segment"
          }
        }
      },
      "FeatureFlagSegmentRuleResponse": {
        "type": "object",
        "description": "A rule condition within a segment",
        "required": [
          "id",
          "field",
          "operator"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the rule"
          },
          "field": {
            "type": "string",
            "description": "The trait/attribute field to match against"
          },
          "operator": {
            "$ref": "#/components/schemas/FeatureFlagOperatorEnum"
          },
          "value": {
            "type": "string",
            "description": "The value to compare against"
          }
        }
      },
      "FeatureFlagSnapshotResponse": {
        "type": "object",
        "description": "Evaluated feature flags for a specific identity",
        "required": [
          "projectId",
          "evaluatedAt",
          "flags"
        ],
        "properties": {
          "projectId": {
            "type": "string",
            "description": "Project ID the flags belong to"
          },
          "evaluatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when the evaluation was performed"
          },
          "flags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvaluatedFeatureFlagResponse"
            },
            "description": "List of evaluated feature flags"
          }
        }
      },
      "EvaluatedFeatureFlagResponse": {
        "type": "object",
        "description": "An evaluated feature flag value (OpenFeature compatible resolution details)",
        "required": [
          "flagKey",
          "enabled",
          "valueType",
          "reason"
        ],
        "properties": {
          "flagKey": {
            "type": "string",
            "description": "Unique key for the flag"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the flag is enabled for this identity"
          },
          "valueType": {
            "$ref": "#/components/schemas/FeatureFlagValueTypeEnum"
          },
          "value": {
            "description": "The evaluated value (type depends on valueType, null if disabled)"
          },
          "variant": {
            "type": "string",
            "description": "OpenFeature variant identifier (e.g., \"control\", \"treatment-a\")"
          },
          "reason": {
            "$ref": "#/components/schemas/OpenFeatureReasonEnum"
          },
          "errorCode": {
            "$ref": "#/components/schemas/OpenFeatureErrorCodeEnum"
          },
          "errorMessage": {
            "type": "string",
            "description": "Human-readable error message if errorCode is present"
          },
          "flagMetadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Optional metadata about the flag (OpenFeature compatible)"
          }
        }
      },
      "PaginatedFeatureFlagResponse": {
        "type": "object",
        "description": "Paginated list of feature flags",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureFlagResponse"
            },
            "description": "List of feature flags for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Number of items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of feature flags"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "PaginatedFeatureFlagSegmentResponse": {
        "type": "object",
        "description": "Paginated list of feature flag segments",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureFlagSegmentResponse"
            },
            "description": "List of segments for this page"
          },
          "page": {
            "type": "integer",
            "description": "Current page number"
          },
          "size": {
            "type": "integer",
            "description": "Number of items per page"
          },
          "totalElements": {
            "type": "integer",
            "description": "Total number of segments"
          },
          "totalPages": {
            "type": "integer",
            "description": "Total number of pages"
          }
        }
      },
      "FeatureFlagUsageResponse": {
        "type": "object",
        "description": "Feature flag usage statistics for billing and analytics",
        "required": [
          "evaluationCount",
          "snapshotCount",
          "mauCount",
          "fromDate",
          "toDate"
        ],
        "properties": {
          "evaluationCount": {
            "type": "integer",
            "format": "int64",
            "description": "Total number of single flag evaluations in the period"
          },
          "snapshotCount": {
            "type": "integer",
            "format": "int64",
            "description": "Total number of snapshot (bulk) evaluations in the period"
          },
          "mauCount": {
            "type": "integer",
            "format": "int64",
            "description": "Number of unique identities (MAU) that evaluated flags in the period"
          },
          "fromDate": {
            "type": "string",
            "format": "date",
            "description": "Start date of the usage period (inclusive)"
          },
          "toDate": {
            "type": "string",
            "format": "date",
            "description": "End date of the usage period (inclusive)"
          }
        }
      },
      "FeatureFlagTimelinePoint": {
        "type": "object",
        "description": "A single data point in the feature flag usage timeline",
        "required": [
          "timestamp",
          "evaluationCount",
          "snapshotCount"
        ],
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date",
            "description": "Date of the usage data point"
          },
          "evaluationCount": {
            "type": "integer",
            "description": "Number of single flag evaluations on this date"
          },
          "snapshotCount": {
            "type": "integer",
            "description": "Number of snapshot (bulk) evaluations on this date"
          }
        }
      },
      "FeatureFlagTimelineResponse": {
        "type": "object",
        "description": "Feature flag usage counts over time for charts",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FeatureFlagTimelinePoint"
            },
            "description": "Timeline data points"
          }
        }
      },
      "FlagConfigurationResponse": {
        "type": "object",
        "description": "Complete feature flag configuration for client-side local evaluation.\nContains all flags, rules, and segments needed to evaluate flags without server calls.\n",
        "required": [
          "projectId",
          "schemaVersion",
          "generatedAt",
          "flags",
          "segments"
        ],
        "properties": {
          "projectId": {
            "type": "string",
            "description": "Project ID this configuration belongs to"
          },
          "schemaVersion": {
            "type": "string",
            "description": "Schema version for SDK compatibility (e.g., \"1.0\")",
            "example": "1.0"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Timestamp when this configuration was generated"
          },
          "etag": {
            "type": "string",
            "description": "ETag for cache validation (use with If-None-Match header)"
          },
          "flags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlagDefinition"
            },
            "description": "List of flag definitions with embedded rules"
          },
          "segments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentDefinition"
            },
            "description": "List of segment definitions with embedded rules"
          }
        }
      },
      "FlagDefinition": {
        "type": "object",
        "description": "A feature flag definition for client-side evaluation",
        "required": [
          "key",
          "valueType",
          "defaultEnabled"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "Unique flag key for evaluation"
          },
          "valueType": {
            "$ref": "#/components/schemas/FeatureFlagValueTypeEnum"
          },
          "defaultEnabled": {
            "type": "boolean",
            "description": "Default enabled state when no rules match"
          },
          "defaultValue": {
            "description": "Default value when flag is enabled (type depends on valueType)"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FlagRuleDefinition"
            },
            "description": "Ordered list of targeting rules (evaluated in priority order)"
          }
        }
      },
      "FlagRuleDefinition": {
        "type": "object",
        "description": "A targeting rule for client-side evaluation",
        "required": [
          "priority",
          "enabled"
        ],
        "properties": {
          "priority": {
            "type": "integer",
            "description": "Rule priority (lower = higher priority, 0 is first)"
          },
          "segmentKey": {
            "type": "string",
            "description": "Segment key to match (null for rules without segment targeting)",
            "nullable": true
          },
          "rolloutPercentage": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Percentage rollout (0-100). Requires identityId for evaluation.",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether to enable the flag when this rule matches"
          },
          "value": {
            "description": "Value to return when this rule matches (type depends on flag valueType)"
          }
        }
      },
      "SegmentDefinition": {
        "type": "object",
        "description": "A targeting segment definition for client-side evaluation",
        "required": [
          "key",
          "rules"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "Unique segment key for rule matching"
          },
          "name": {
            "type": "string",
            "description": "Human-readable segment name"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SegmentRuleDefinition"
            },
            "description": "List of rules that define this segment (AND logic)"
          }
        }
      },
      "SegmentRuleDefinition": {
        "type": "object",
        "description": "A single rule condition within a segment",
        "required": [
          "field",
          "operator"
        ],
        "properties": {
          "field": {
            "type": "string",
            "description": "The context attribute field to match against"
          },
          "operator": {
            "$ref": "#/components/schemas/FeatureFlagOperatorEnum"
          },
          "value": {
            "type": "string",
            "description": "The value to compare against (interpretation depends on operator)",
            "nullable": true
          }
        }
      },
      "IntegrationProviderEnum": {
        "type": "string",
        "enum": [
          "slack",
          "google_analytics"
        ],
        "description": "Supported integration providers"
      },
      "IntegrationStatusEnum": {
        "type": "string",
        "enum": [
          "active",
          "inactive",
          "error"
        ],
        "description": "Status of an integration connection"
      },
      "IntegrationFeatureTypeEnum": {
        "type": "string",
        "enum": [
          "custom_events",
          "feature_flags",
          "ota_updates",
          "builds"
        ],
        "description": "Feature types that can trigger integration notifications"
      },
      "IntegrationSubscriptionRuleOperatorEnum": {
        "type": "string",
        "enum": [
          "equals",
          "contains",
          "starts_with",
          "ends_with"
        ],
        "description": "Operators for subscription filtering rules"
      },
      "IntegrationSubscriptionRuleFieldEnum": {
        "type": "string",
        "enum": [
          "event_name",
          "channel",
          "user_id",
          "tag"
        ],
        "description": "Fields that can be used in subscription filtering rules"
      },
      "IntegrationResponse": {
        "type": "object",
        "description": "Organization-level integration details",
        "required": [
          "id",
          "provider",
          "status",
          "connectedAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier for the integration"
          },
          "provider": {
            "$ref": "#/components/schemas/IntegrationProviderEnum"
          },
          "status": {
            "$ref": "#/components/schemas/IntegrationStatusEnum"
          },
          "reconnectRequired": {
            "type": "boolean",
            "description": "True when the grant this install holds no longer covers everything the app asks for, so the workspace has to go through OAuth again. An active install in this state keeps working for anything we send outbound while silently receiving nothing — the assistant is unreachable from chat until it is reconnected. Installs made before granted scopes were recorded read as true, because there is no way to tell what they were given."
          },
          "teamId": {
            "type": "string",
            "description": "Slack workspace ID"
          },
          "teamName": {
            "type": "string",
            "description": "Slack workspace name"
          },
          "connectedBy": {
            "type": "string",
            "format": "uuid",
            "description": "User ID who connected the integration"
          },
          "connectedByName": {
            "type": "string",
            "description": "Name of the user who connected the integration"
          },
          "connectedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the integration was connected"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the integration was last updated"
          }
        }
      },
      "SlackChannelResponse": {
        "type": "object",
        "description": "A Slack channel available for notifications",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Slack channel ID"
          },
          "name": {
            "type": "string",
            "description": "Channel name (without"
          },
          "isPrivate": {
            "type": "boolean",
            "description": "Whether the channel is private"
          }
        }
      },
      "SlackChannelListResponse": {
        "type": "object",
        "description": "List of available Slack channels",
        "required": [
          "channels"
        ],
        "properties": {
          "channels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SlackChannelResponse"
            }
          }
        }
      },
      "IntegrationSubscriptionRule": {
        "type": "object",
        "description": "A filtering rule for the subscription",
        "required": [
          "field",
          "operator",
          "value"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Rule ID (only present in responses)"
          },
          "field": {
            "$ref": "#/components/schemas/IntegrationSubscriptionRuleFieldEnum"
          },
          "operator": {
            "$ref": "#/components/schemas/IntegrationSubscriptionRuleOperatorEnum"
          },
          "value": {
            "type": "string",
            "description": "Value to match against",
            "example": "payment"
          }
        }
      },
      "CreateIntegrationSubscriptionRequest": {
        "type": "object",
        "description": "Request to create a new integration subscription",
        "required": [
          "featureType",
          "channelId",
          "channelName"
        ],
        "properties": {
          "featureType": {
            "$ref": "#/components/schemas/IntegrationFeatureTypeEnum"
          },
          "channelId": {
            "type": "string",
            "description": "Slack channel ID"
          },
          "channelName": {
            "type": "string",
            "description": "Slack channel name (for display)"
          },
          "enabled": {
            "type": "boolean",
            "default": true,
            "description": "Whether the subscription is active"
          },
          "forceNotify": {
            "type": "boolean",
            "default": false,
            "description": "When true, sends notifications for ALL matching events regardless of notify flag in the event request"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationSubscriptionRule"
            },
            "description": "Optional filtering rules (if empty, all events are sent)"
          }
        }
      },
      "UpdateIntegrationSubscriptionRequest": {
        "type": "object",
        "description": "Request to update an integration subscription",
        "properties": {
          "channelId": {
            "type": "string",
            "description": "Slack channel ID"
          },
          "channelName": {
            "type": "string",
            "description": "Slack channel name"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the subscription is active"
          },
          "forceNotify": {
            "type": "boolean",
            "description": "When true, sends notifications for ALL matching events regardless of notify flag"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationSubscriptionRule"
            },
            "description": "Filtering rules (replaces existing rules)"
          }
        }
      },
      "IntegrationSubscriptionResponse": {
        "type": "object",
        "description": "Project-level integration subscription",
        "required": [
          "id",
          "integrationId",
          "projectId",
          "featureType",
          "channelId",
          "channelName",
          "enabled",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Subscription ID"
          },
          "integrationId": {
            "type": "string",
            "format": "uuid",
            "description": "Parent integration ID"
          },
          "projectId": {
            "type": "string",
            "format": "uuid",
            "description": "Project this subscription belongs to"
          },
          "projectName": {
            "type": "string",
            "description": "Project name (for display)"
          },
          "featureType": {
            "$ref": "#/components/schemas/IntegrationFeatureTypeEnum"
          },
          "channelId": {
            "type": "string",
            "description": "Slack channel ID"
          },
          "channelName": {
            "type": "string",
            "description": "Slack channel name"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the subscription is active"
          },
          "forceNotify": {
            "type": "boolean",
            "description": "When true, sends notifications for ALL matching events regardless of notify flag"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationSubscriptionRule"
            },
            "description": "Filtering rules"
          },
          "createdBy": {
            "type": "string",
            "format": "uuid",
            "description": "User who created the subscription"
          },
          "createdByName": {
            "type": "string",
            "description": "Name of creator"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginatedIntegrationSubscriptionResponse": {
        "type": "object",
        "description": "Paginated list of integration subscriptions",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationSubscriptionResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "ImportSourceEnum": {
        "type": "string",
        "enum": [
          "ga4"
        ],
        "description": "External analytics platform an import pulls data from"
      },
      "DataImportStatusEnum": {
        "type": "string",
        "enum": [
          "RUNNING",
          "PAUSED",
          "CANCELLED",
          "COMPLETED",
          "FAILED",
          "DATA_DELETED"
        ],
        "description": "Derived import status. Mirrors the backing background job while data is present; DATA_DELETED once the imported rows have been wiped.\n"
      },
      "StartDataImportRequest": {
        "type": "object",
        "required": [
          "source",
          "propertyId",
          "startDate",
          "endDate"
        ],
        "properties": {
          "source": {
            "$ref": "#/components/schemas/ImportSourceEnum"
          },
          "propertyId": {
            "type": "string",
            "description": "Provider-native property/site id (GA4 numeric property id)"
          },
          "propertyName": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable property name, stored for display"
          },
          "startDate": {
            "type": "string",
            "format": "date",
            "description": "First day to import (inclusive, property-timezone day)"
          },
          "endDate": {
            "type": "string",
            "format": "date",
            "description": "Last day to import (inclusive); must be before today"
          }
        }
      },
      "DataImportResponse": {
        "type": "object",
        "required": [
          "id",
          "source",
          "propertyId",
          "startDate",
          "endDate",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "source": {
            "$ref": "#/components/schemas/ImportSourceEnum"
          },
          "propertyId": {
            "type": "string"
          },
          "propertyName": {
            "type": "string",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "format": "date"
          },
          "endDate": {
            "type": "string",
            "format": "date"
          },
          "status": {
            "$ref": "#/components/schemas/DataImportStatusEnum"
          },
          "totalChunks": {
            "type": "integer",
            "description": "Total day-chunks in the import range"
          },
          "completedChunks": {
            "type": "integer"
          },
          "failedChunks": {
            "type": "integer"
          },
          "eventsWritten": {
            "type": "integer",
            "format": "int64"
          },
          "sessionsWritten": {
            "type": "integer",
            "format": "int64"
          },
          "pageviewsWritten": {
            "type": "integer",
            "format": "int64"
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Ga4PropertyResponse": {
        "type": "object",
        "required": [
          "propertyId",
          "displayName"
        ],
        "properties": {
          "propertyId": {
            "type": "string",
            "description": "GA4 numeric property id"
          },
          "displayName": {
            "type": "string"
          },
          "accountName": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Ga4PropertyListResponse": {
        "type": "object",
        "required": [
          "properties"
        ],
        "properties": {
          "properties": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Ga4PropertyResponse"
            }
          }
        }
      },
      "SlackDeliveryResponse": {
        "type": "object",
        "description": "Slack message delivery record",
        "required": [
          "id",
          "subscriptionId",
          "eventCount",
          "channelId",
          "success",
          "deliveredAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "subscriptionId": {
            "type": "string",
            "format": "uuid"
          },
          "batchId": {
            "type": "string",
            "format": "uuid",
            "description": "Batch ID if multiple events were aggregated"
          },
          "eventCount": {
            "type": "integer",
            "description": "Number of events in this delivery"
          },
          "channelId": {
            "type": "string"
          },
          "channelName": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          },
          "errorMessage": {
            "type": "string"
          },
          "deliveredAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginatedSlackDeliveryResponse": {
        "type": "object",
        "description": "Paginated list of Slack deliveries",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SlackDeliveryResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "BillingPlanTypeEnum": {
        "type": "string",
        "enum": [
          "standard",
          "custom"
        ],
        "description": "Type of billing plan"
      },
      "BillingPeriodEnum": {
        "type": "string",
        "enum": [
          "monthly",
          "yearly",
          "custom"
        ],
        "description": "Billing cycle period"
      },
      "BillingSubscriptionStatusEnum": {
        "type": "string",
        "enum": [
          "active",
          "trialing",
          "past_due",
          "canceled",
          "paused",
          "suspended"
        ],
        "description": "Subscription lifecycle status"
      },
      "BillingFeatureValueTypeEnum": {
        "type": "string",
        "enum": [
          "boolean",
          "numeric",
          "unlimited",
          "string"
        ],
        "description": "How feature values are interpreted"
      },
      "BillingFeatureCodeEnum": {
        "type": "string",
        "enum": [
          "max_organizations",
          "max_projects",
          "max_team_members",
          "max_feature_flags",
          "data_retention_days",
          "events_per_month",
          "feature_flag_segments",
          "audit_logs",
          "sso",
          "webhooks",
          "api_access",
          "priority_support",
          "custom_events_enabled",
          "custom_dashboards",
          "ai_visibility_max_prompts",
          "ai_visibility_max_personas",
          "bot_events_per_month",
          "ai_visibility_runs_per_month",
          "engagement_max_keywords",
          "ai_visibility_providers",
          "ai_visibility_exploration_providers",
          "ai_visibility_max_projects",
          "ai_visibility_run_interval_days",
          "ai_visibility_regions",
          "monthly_budget_usd",
          "free_monthly_budget_usd",
          "backlinks_refresh_interval_days",
          "backlinks_pulls_per_day",
          "workflows_enabled",
          "max_active_workflows",
          "workflow_runs_per_month"
        ],
        "description": "Available billing feature codes"
      },
      "BillingPlanResponse": {
        "type": "object",
        "description": "A billing plan available in the system",
        "required": [
          "id",
          "name",
          "slug",
          "type"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique plan identifier"
          },
          "name": {
            "type": "string",
            "description": "Plan display name"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly plan identifier"
          },
          "description": {
            "type": "string",
            "description": "Plan description"
          },
          "type": {
            "$ref": "#/components/schemas/BillingPlanTypeEnum"
          },
          "basePriceCents": {
            "type": "integer",
            "description": "Base price in cents (null for custom pricing)"
          },
          "currency": {
            "type": "string",
            "description": "Currency code (e.g., USD)",
            "default": "USD"
          },
          "billingPeriod": {
            "$ref": "#/components/schemas/BillingPeriodEnum"
          },
          "trialDays": {
            "type": "integer",
            "description": "Number of trial days",
            "default": 0
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillingPlanFeatureResponse"
            },
            "description": "Features included in this plan"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BillingPlanFeatureResponse": {
        "type": "object",
        "description": "A feature included in a billing plan",
        "required": [
          "featureCode",
          "featureName",
          "value",
          "valueType"
        ],
        "properties": {
          "featureCode": {
            "$ref": "#/components/schemas/BillingFeatureCodeEnum"
          },
          "featureName": {
            "type": "string",
            "description": "Feature display name"
          },
          "value": {
            "type": "string",
            "description": "Feature value (e.g., \"10\", \"true\", \"unlimited\")"
          },
          "valueType": {
            "$ref": "#/components/schemas/BillingFeatureValueTypeEnum"
          },
          "category": {
            "type": "string",
            "description": "Feature category (e.g., limits, security, support)"
          }
        }
      },
      "BillingFeatureResponse": {
        "type": "object",
        "description": "A feature definition in the billing system",
        "required": [
          "id",
          "code",
          "name",
          "valueType"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique feature identifier"
          },
          "code": {
            "type": "string",
            "description": "Feature code (e.g., max_projects)"
          },
          "name": {
            "type": "string",
            "description": "Feature display name"
          },
          "description": {
            "type": "string",
            "description": "Feature description"
          },
          "valueType": {
            "$ref": "#/components/schemas/BillingFeatureValueTypeEnum"
          },
          "category": {
            "type": "string",
            "description": "Feature category"
          },
          "displayOrder": {
            "type": "integer",
            "description": "Sort order for UI display"
          }
        }
      },
      "SubscriptionStatusResponse": {
        "type": "object",
        "description": "Lightweight subscription status for banners and guards. Available to all org members.",
        "required": [
          "organizationStatus",
          "planName"
        ],
        "properties": {
          "organizationStatus": {
            "type": "string",
            "enum": [
              "active",
              "suspended",
              "trial"
            ],
            "description": "Organization-level status"
          },
          "trialEndsAt": {
            "type": "string",
            "format": "date-time",
            "description": "When trial period ends (only present when status is trial)"
          },
          "planName": {
            "type": "string",
            "description": "Name of the current plan"
          }
        }
      },
      "BillingSubscriptionResponse": {
        "type": "object",
        "description": "Organization's billing subscription",
        "required": [
          "id",
          "organizationId",
          "plan",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Subscription unique identifier"
          },
          "organizationId": {
            "type": "string",
            "description": "Organization this subscription belongs to"
          },
          "plan": {
            "$ref": "#/components/schemas/BillingPlanResponse"
          },
          "status": {
            "$ref": "#/components/schemas/BillingSubscriptionStatusEnum"
          },
          "organizationStatus": {
            "type": "string",
            "enum": [
              "active",
              "suspended",
              "trial"
            ],
            "description": "Organization-level status (active, suspended, or trial)"
          },
          "currentPeriodStart": {
            "type": "string",
            "format": "date-time",
            "description": "Start of current billing period"
          },
          "currentPeriodEnd": {
            "type": "string",
            "format": "date-time",
            "description": "End of current billing period"
          },
          "trialEndsAt": {
            "type": "string",
            "format": "date-time",
            "description": "When trial period ends"
          },
          "canceledAt": {
            "type": "string",
            "format": "date-time",
            "description": "When subscription was canceled"
          },
          "cancelAtPeriodEnd": {
            "type": "boolean",
            "description": "Whether subscription will cancel at period end"
          },
          "pendingPlan": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BillingPlanResponse"
              }
            ],
            "description": "Plan the organization is scheduled to switch to at the end of the current billing period (a deferred downgrade). Null when no change is scheduled."
          },
          "pendingPlanEffectiveAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the scheduled plan change takes effect (the end of the current billing period). Present only when pendingPlan is set."
          },
          "customPriceCents": {
            "type": "integer",
            "description": "Custom negotiated price (if different from plan price)"
          },
          "currency": {
            "type": "string",
            "description": "Currency code"
          },
          "featureOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillingFeatureOverrideResponse"
            },
            "description": "Feature overrides applied to this subscription"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BillingFeatureOverrideResponse": {
        "type": "object",
        "description": "A feature override applied to a subscription",
        "required": [
          "id",
          "featureCode",
          "featureName",
          "value"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Override unique identifier"
          },
          "featureCode": {
            "$ref": "#/components/schemas/BillingFeatureCodeEnum"
          },
          "featureName": {
            "type": "string",
            "description": "Feature display name"
          },
          "value": {
            "type": "string",
            "description": "Override value"
          },
          "reason": {
            "type": "string",
            "description": "Reason for the override"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "When this override expires"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BillingUsageResponse": {
        "type": "object",
        "description": "Current usage statistics for the subscription",
        "required": [
          "subscriptionId",
          "periodStart",
          "periodEnd",
          "usage"
        ],
        "properties": {
          "subscriptionId": {
            "type": "string",
            "description": "Subscription identifier"
          },
          "periodStart": {
            "type": "string",
            "format": "date",
            "description": "Start of usage period"
          },
          "periodEnd": {
            "type": "string",
            "format": "date",
            "description": "End of usage period"
          },
          "usage": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillingUsageItemResponse"
            },
            "description": "Usage breakdown by feature"
          },
          "creditBalance": {
            "type": "number",
            "description": "Remaining prepaid credits across all active lots"
          }
        }
      },
      "BillingUsageItemResponse": {
        "type": "object",
        "description": "Usage for a specific metered feature",
        "required": [
          "featureCode",
          "featureName",
          "currentUsage",
          "limit"
        ],
        "properties": {
          "featureCode": {
            "$ref": "#/components/schemas/BillingFeatureCodeEnum"
          },
          "featureName": {
            "type": "string",
            "description": "Feature display name"
          },
          "currentUsage": {
            "type": "integer",
            "format": "int64",
            "description": "Current usage count"
          },
          "limit": {
            "type": "string",
            "description": "Usage limit (\"unlimited\" or numeric value)"
          },
          "includedUnits": {
            "type": "integer",
            "format": "int64",
            "description": "Units included in plan"
          },
          "percentUsed": {
            "type": "number",
            "format": "double",
            "description": "Percentage of limit used"
          },
          "creditUnitsAvailable": {
            "type": "integer",
            "format": "int64",
            "description": "Extra units prepaid credits currently buy beyond the plan limit (absent for features credits do not apply to)\n"
          }
        }
      },
      "BillingEntitlementResponse": {
        "type": "object",
        "description": "Result of checking an entitlement",
        "required": [
          "featureCode",
          "hasAccess"
        ],
        "properties": {
          "featureCode": {
            "$ref": "#/components/schemas/BillingFeatureCodeEnum"
          },
          "hasAccess": {
            "type": "boolean",
            "description": "Whether access is granted"
          },
          "value": {
            "type": "string",
            "description": "The effective feature value"
          },
          "limit": {
            "type": "integer",
            "description": "Numeric limit (if applicable)"
          },
          "currentUsage": {
            "type": "integer",
            "description": "Current usage (if applicable)"
          },
          "isUnlimited": {
            "type": "boolean",
            "description": "Whether the feature is unlimited"
          },
          "message": {
            "type": "string",
            "description": "Human-readable message about access"
          }
        }
      },
      "BillingPlanListResponse": {
        "type": "object",
        "description": "List of available billing plans",
        "required": [
          "plans"
        ],
        "properties": {
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillingPlanResponse"
            },
            "description": "Available billing plans"
          }
        }
      },
      "CreateCheckoutSessionRequest": {
        "type": "object",
        "description": "Request to create a Stripe checkout session",
        "required": [
          "planId"
        ],
        "properties": {
          "planId": {
            "type": "string",
            "description": "ID of the plan to upgrade to"
          }
        }
      },
      "CheckoutSessionResponse": {
        "type": "object",
        "description": "Result of asking to move onto a plan. A new subscription returns checkoutUrl and sessionId to redirect to. Every other outcome is settled server-side and returns message plus the one flag naming what happened.",
        "properties": {
          "checkoutUrl": {
            "type": "string",
            "description": "URL to redirect the user to for checkout (for new subscriptions)"
          },
          "sessionId": {
            "type": "string",
            "description": "Stripe checkout session ID (for new subscriptions)"
          },
          "message": {
            "type": "string",
            "description": "Human-readable description of the outcome, set on every non-checkout branch"
          },
          "updated": {
            "type": "string",
            "description": "Set to \"true\" when an existing subscription was updated directly (no checkout needed)"
          },
          "scheduled": {
            "type": "string",
            "description": "Set to \"true\" when a downgrade was scheduled for the end of the billing period"
          },
          "cancelled": {
            "type": "string",
            "description": "Set to \"true\" when a previously scheduled plan change was cancelled"
          },
          "unchanged": {
            "type": "string",
            "description": "Set to \"true\" when the organization was already on the requested plan"
          }
        }
      },
      "CreateBillingPortalRequest": {
        "type": "object",
        "description": "Request to create a Stripe billing portal session",
        "properties": {
          "returnUrl": {
            "type": "string",
            "description": "URL to redirect the user to after leaving the portal"
          }
        }
      },
      "BillingPortalResponse": {
        "type": "object",
        "description": "Response containing billing portal session details",
        "required": [
          "portalUrl"
        ],
        "properties": {
          "portalUrl": {
            "type": "string",
            "description": "URL to redirect the user to for the billing portal"
          }
        }
      },
      "SubscriptionActionResponse": {
        "type": "object",
        "description": "Response for subscription actions (reactivate, cancel, etc.)",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "description": "Status of the action (e.g., \"reactivated\", \"canceled\")"
          }
        }
      },
      "CancelScheduledChangeResponse": {
        "type": "object",
        "description": "Response for cancelling a scheduled (deferred) plan change",
        "required": [
          "cancelled"
        ],
        "properties": {
          "cancelled": {
            "type": "boolean",
            "description": "True when a scheduled plan change was found and cancelled"
          },
          "message": {
            "type": "string",
            "description": "Human-readable result message"
          },
          "plan": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BillingPlanResponse"
              }
            ],
            "description": "The plan the organization remains on after cancelling the scheduled change"
          }
        }
      },
      "BillingTransactionStatusEnum": {
        "type": "string",
        "enum": [
          "paid",
          "open",
          "draft",
          "uncollectible",
          "void"
        ],
        "description": "Status of a billing transaction/invoice"
      },
      "BillingTransactionResponse": {
        "type": "object",
        "description": "A billing transaction (Stripe invoice)",
        "required": [
          "id",
          "amount",
          "currency",
          "status",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stripe invoice ID"
          },
          "invoiceNumber": {
            "type": "string",
            "description": "Invoice number (e.g., inv_XXXX)"
          },
          "invoiceUrl": {
            "type": "string",
            "description": "Stripe hosted invoice URL"
          },
          "amount": {
            "type": "integer",
            "description": "Amount in cents"
          },
          "currency": {
            "type": "string",
            "description": "Currency code (e.g., usd)"
          },
          "status": {
            "$ref": "#/components/schemas/BillingTransactionStatusEnum"
          },
          "planName": {
            "type": "string",
            "description": "Local plan name"
          },
          "periodStart": {
            "type": "string",
            "format": "date-time",
            "description": "Billing period start"
          },
          "periodEnd": {
            "type": "string",
            "format": "date-time",
            "description": "Billing period end"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "Invoice creation date"
          }
        }
      },
      "BillingTransactionListResponse": {
        "type": "object",
        "description": "Paginated list of billing transactions using cursor-based pagination",
        "required": [
          "data",
          "hasMore"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillingTransactionResponse"
            }
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether there are more results after this page"
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor for fetching the next page (last invoice ID)",
            "nullable": true
          }
        }
      },
      "SubmitFeedbackRequest": {
        "type": "object",
        "description": "Request to submit in-app feedback",
        "required": [
          "message",
          "page"
        ],
        "properties": {
          "message": {
            "type": "string",
            "maxLength": 10000,
            "description": "The feedback message content",
            "example": "The export button on the sessions page is hard to find."
          },
          "page": {
            "type": "string",
            "maxLength": 1024,
            "description": "The page (route/path) the user was on when submitting feedback",
            "example": "/acme/sessions"
          }
        }
      },
      "FeedbackSubmissionResponse": {
        "type": "object",
        "description": "Response after successful feedback submission",
        "required": [
          "message",
          "id"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Success message",
            "example": "Thank you for your feedback!"
          },
          "id": {
            "type": "string",
            "description": "Unique identifier for the submitted feedback",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        }
      },
      "AiVisibilityBrandRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Brand display name (always matched as an alias)"
          },
          "primaryDomain": {
            "type": "string",
            "maxLength": 255,
            "description": "Registrable domain (eTLD+1), e.g. \"example.com\" — drives SELF/COMPETITOR citation classification"
          },
          "isSelf": {
            "type": "boolean",
            "default": false,
            "description": "TRUE for the customer's own brand (one per project); FALSE for a competitor"
          },
          "active": {
            "type": "boolean",
            "default": true
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Alternative names matched in AI answers (stored lowercased)"
          },
          "excludedTopicIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Topics this competitor is NOT tracked in — it is treated as absent from every run tagged with one of them, so those runs leave both its numerator and its denominator. Replaces the whole set: send an empty array to clear it. On PUT, OMITTING the field leaves the current scope untouched (unlike aliases), so a client that predates this field cannot wipe it. Rejected for the self brand; uncategorized prompts always count."
          }
        }
      },
      "AiVisibilityBrandResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "primaryDomain": {
            "type": "string",
            "nullable": true
          },
          "isSelf": {
            "type": "boolean"
          },
          "active": {
            "type": "boolean"
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "excludedTopicIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Topics this competitor is not tracked in; empty means tracked everywhere"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AiVisibilityPromptRequest": {
        "description": "A prompt to create. Creation is the only place an assignment travels with the prompt's own fields — afterwards, topic and persona are moved by `prompts/bulk-move` and `prompts/bulk-assign-persona`.",
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 1024
          },
          "intentTier": {
            "type": "string",
            "default": "category",
            "description": "Free-form intent tier ('buying' | 'category' | 'branded')"
          },
          "locale": {
            "type": "string",
            "default": "en-US"
          },
          "active": {
            "type": "boolean",
            "default": true
          },
          "topicId": {
            "type": "string",
            "nullable": true,
            "description": "Topic to file the new prompt under. Omitted or null leaves it uncategorised."
          },
          "personaId": {
            "type": "string",
            "nullable": true,
            "description": "Persona to write the new prompt for. Omitted or null leaves it unassigned."
          }
        }
      },
      "AiVisibilityPromptUpdateRequest": {
        "description": "Edits a prompt's own fields, and replaces every one of them — an omitted `locale` or `active` returns to its default. It deliberately carries no `topicId` or `personaId`: assignment is what `prompts/bulk-move` and `prompts/bulk-assign-persona` are for, so renaming a prompt cannot silently clear the topic or persona somebody filed it under.",
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 1024
          },
          "intentTier": {
            "type": "string",
            "default": "category",
            "description": "Free-form intent tier ('buying' | 'category' | 'branded')"
          },
          "locale": {
            "type": "string",
            "default": "en-US"
          },
          "active": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "AiVisibilityPromptSuggestionsRequest": {
        "type": "object",
        "required": [
          "brandName"
        ],
        "properties": {
          "brandName": {
            "type": "string",
            "maxLength": 255
          },
          "primaryDomain": {
            "type": "string",
            "maxLength": 255
          },
          "count": {
            "type": "integer",
            "default": 8,
            "description": "Number of prompts to suggest (1-15)"
          },
          "personaIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Active persona ids to write for. The generated queries carry each persona's context as a natural clause (\"...for a 20-person remote design agency\"); omitted or empty generates persona-neutral queries.\n"
          }
        }
      },
      "AiVisibilityPromptSuggestion": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string"
          },
          "personaId": {
            "type": "string",
            "nullable": true,
            "description": "The persona this query was written for, if any."
          },
          "personaName": {
            "type": "string",
            "nullable": true
          },
          "reason": {
            "type": "string",
            "description": "One line on why this query is worth tracking."
          },
          "intentTier": {
            "type": "string",
            "description": "Suggested tier ('buying' | 'category' | 'branded')"
          }
        }
      },
      "AiVisibilityPromptSuggestionsResponse": {
        "type": "object",
        "properties": {
          "suggestions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPromptSuggestion"
            },
            "description": "Candidate prompts for review — not persisted"
          }
        }
      },
      "CreateAiVisibilityPromptsRequest": {
        "type": "object",
        "required": [
          "prompts"
        ],
        "properties": {
          "prompts": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPromptRequest"
            }
          }
        }
      },
      "AiVisibilityPromptBulkMoveRequest": {
        "type": "object",
        "required": [
          "promptIds"
        ],
        "properties": {
          "promptIds": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "uniqueItems": true,
            "items": {
              "type": "string"
            }
          },
          "topicId": {
            "type": "string",
            "nullable": true,
            "description": "Topic to move every listed prompt into. Omitted or null moves them out of whatever topic they are in. There is no \"leave the topic alone\" case — setting the topic is the entire operation, which is why null can mean unassign here without ambiguity."
          }
        }
      },
      "AiVisibilityPromptBulkAssignPersonaRequest": {
        "type": "object",
        "required": [
          "promptIds"
        ],
        "properties": {
          "promptIds": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "uniqueItems": true,
            "items": {
              "type": "string"
            }
          },
          "personaId": {
            "type": "string",
            "nullable": true,
            "description": "Persona to assign to every listed prompt. Omitted or null unassigns them. As with the topic, setting the persona is the entire operation — the call never touches a prompt's topic or text."
          }
        }
      },
      "AiVisibilityPromptBulkDeleteRequest": {
        "type": "object",
        "required": [
          "promptIds"
        ],
        "properties": {
          "promptIds": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "uniqueItems": true,
            "items": {
              "type": "string"
            }
          }
        }
      },
      "AiVisibilityPromptBulkResponse": {
        "type": "object",
        "properties": {
          "affected": {
            "type": "integer",
            "description": "How many prompts the call changed."
          }
        }
      },
      "AiVisibilityPromptResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "intentTier": {
            "type": "string"
          },
          "locale": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          },
          "topicId": {
            "type": "string",
            "nullable": true
          },
          "topicName": {
            "type": "string",
            "nullable": true
          },
          "personaId": {
            "type": "string",
            "nullable": true
          },
          "personaName": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AiVisibilityJobEstimateResponse": {
        "type": "object",
        "properties": {
          "promptCount": {
            "type": "integer",
            "description": "Active prompts that would run"
          },
          "maxPrompts": {
            "type": "integer",
            "nullable": true,
            "description": "Plan limit on active prompts (null when unlimited)"
          },
          "enabledProviders": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Engines that would run for this organization (plan-gated)"
          },
          "withinBudget": {
            "type": "boolean",
            "description": "Whether starting this run is allowed under the organization's monthly limit (internal cost figures are never exposed)"
          },
          "analysisConfigured": {
            "type": "boolean",
            "description": "Whether the AI analysis pass (entity extraction) is configured; required for an analysis run to start"
          }
        }
      },
      "AiVisibilityProvidersResponse": {
        "type": "object",
        "required": [
          "providers"
        ],
        "properties": {
          "providers": {
            "type": "array",
            "description": "Engines the organization's plan allows AND the server has keys for (AiProvider names; never includes the ALL sentinel)",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "AiVisibilityRegionEnum": {
        "type": "string",
        "description": "A geographic vantage point a prompt is asked from. One region aggregates one or more concrete countries (server config), so EU answers from several European markets roll up into one bucket.\n",
        "enum": [
          "US",
          "EU"
        ]
      },
      "AiVisibilityRegionsResponse": {
        "type": "object",
        "required": [
          "regions"
        ],
        "properties": {
          "regions": {
            "type": "array",
            "description": "The regions this project is measured from, resolved server-side, never empty (US at minimum). Read-only: the set is granted per organization by support, not chosen by the customer, so there is no corresponding write endpoint. A region is the whole unit of meaning here — the concrete countries it samples are an internal detail and are deliberately not exposed.\n",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityRegionEnum"
            }
          }
        }
      },
      "AiVisibilityScheduleResponse": {
        "type": "object",
        "properties": {
          "autoRunEnabled": {
            "type": "boolean",
            "description": "Whether analyses run automatically for this project (organization has an active paid subscription)"
          },
          "intervalHours": {
            "type": "integer",
            "description": "Hours between automatic runs"
          },
          "lastRunAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the most recent analysis job was started (null when never run)"
          },
          "nextRunAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the next automatic run is due (null when autoRunEnabled is false)"
          },
          "secondsUntilNextRun": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Seconds until nextRunAt, floored at 0 (null when autoRunEnabled is false)"
          },
          "manualRunAllowed": {
            "type": "boolean",
            "description": "Whether the organization may start a manual analysis right now"
          },
          "manualRunBlockedReason": {
            "type": "string",
            "nullable": true,
            "enum": [
              "SUSPENDED_FREE_RUN_USED"
            ],
            "description": "Why manual runs are blocked (null when manualRunAllowed is true)"
          }
        }
      },
      "AiVisibilityJobResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "RUNNING",
              "PAUSE_REQUESTED",
              "PAUSED",
              "CANCEL_REQUESTED",
              "CANCELLED",
              "COMPLETED",
              "FAILED"
            ]
          },
          "totalUnits": {
            "type": "integer"
          },
          "completedUnits": {
            "type": "integer"
          },
          "failedUnits": {
            "type": "integer"
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI engines this job ran (or is running) units against"
          }
        }
      },
      "SiteAuditCheckId": {
        "type": "string",
        "description": "One audit capability the user can see in the start dialog. Core crawl steps (ROBOTS, LLMS_TXT, SITEMAP, HOMEPAGE, PAGE_CRAWL) always run; the rest can be deselected per run.",
        "enum": [
          "ROBOTS",
          "LLMS_TXT",
          "SITEMAP",
          "HOMEPAGE",
          "PAGE_CRAWL",
          "WAF_PROBE",
          "ANALYTICS",
          "PAGE_CHECKS",
          "CONSISTENCY",
          "SPEC_COMPLIANCE",
          "AI_READ",
          "SIMILARITY",
          "LIGHTHOUSE"
        ]
      },
      "SiteAuditAvailableCheck": {
        "type": "object",
        "description": "One entry of the start dialog's check list, served from the auditor registry so the dashboard never hardcodes check names — a new capability appears here with zero frontend work.",
        "required": [
          "id",
          "label",
          "description",
          "selectable",
          "defaultSelected"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/SiteAuditCheckId"
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "selectable": {
            "type": "boolean",
            "description": "False for core crawl steps, which always run."
          },
          "defaultSelected": {
            "type": "boolean",
            "description": "Always true today — every check starts checked."
          },
          "unavailableReason": {
            "type": "string",
            "nullable": true,
            "description": "Set when the check cannot run on this server or plan (no provider configured, no AI model). The dialog shows it disabled with this sentence."
          }
        }
      },
      "SiteAuditConfigResponse": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "nullable": true,
            "description": "Domain to audit (registrable eTLD+1) — the project's website domain, which is its only source. Null when the project has no website set."
          },
          "suggestedDomain": {
            "type": "string",
            "nullable": true,
            "description": "Prefill suggestion when no website is set: the AI-visibility self-brand's primary domain. Equal to `domain` once one is set."
          },
          "availableChecks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditAvailableCheck"
            }
          }
        }
      },
      "SiteAuditProgress": {
        "type": "object",
        "properties": {
          "totalUnits": {
            "type": "integer"
          },
          "completedUnits": {
            "type": "integer"
          },
          "failedUnits": {
            "type": "integer"
          }
        }
      },
      "SiteAuditCategoryScores": {
        "type": "object",
        "properties": {
          "crawlerAccess": {
            "type": "integer",
            "nullable": true
          },
          "machineReadability": {
            "type": "integer",
            "nullable": true
          },
          "analytics": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "SiteAuditCheckResponse": {
        "type": "object",
        "description": "One audit check verdict, carrying the copy that explains it. The wording is served rather than kept in the frontend because the dashboard is not the only reader — the MCP tools hand these verdicts straight to an assistant.",
        "required": [
          "title",
          "description",
          "detail",
          "fix"
        ],
        "properties": {
          "checkType": {
            "type": "string",
            "enum": [
              "ROBOTS_TXT_VALID",
              "AI_CRAWLERS_ALLOWED",
              "SITEMAP_PRESENT_VALID",
              "LLMS_TXT_PRESENT",
              "AI_BOT_EDGE_BLOCKING",
              "HTTPS_REDIRECT_HEALTH",
              "CONTENT_IN_INITIAL_HTML",
              "TITLE_META_DESCRIPTION",
              "STRUCTURED_DATA_JSONLD",
              "OPENGRAPH_TAGS",
              "CANONICAL_TAGS",
              "HEADING_HIERARCHY",
              "PAGE_HEALTH",
              "AI_CRAWLER_VISITS_30D",
              "AI_CRAWL_FRESHNESS",
              "AI_SHARE_OF_VOICE"
            ]
          },
          "category": {
            "type": "string",
            "enum": [
              "CRAWLER_ACCESS",
              "MACHINE_READABILITY",
              "ANALYTICS"
            ]
          },
          "title": {
            "type": "string",
            "description": "What the check is, phrased as the good outcome"
          },
          "description": {
            "type": "string",
            "description": "Why the check matters — the same sentence whatever the verdict"
          },
          "status": {
            "type": "string",
            "enum": [
              "PASS",
              "FAIL",
              "WARNING",
              "NOT_APPLICABLE",
              "ERROR"
            ]
          },
          "detail": {
            "type": "string",
            "description": "What this audit found, in a sentence"
          },
          "fix": {
            "type": "string",
            "description": "What to do about it — worth showing only when the check is not passing"
          },
          "weight": {
            "type": "integer"
          },
          "details": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Structured evidence for the UI (per-bot verdicts, failing URLs, probe statuses)"
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SiteAuditPageResponse": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "HOMEPAGE",
              "SITEMAP",
              "LINK"
            ]
          },
          "httpStatus": {
            "type": "integer",
            "nullable": true
          },
          "contentBytes": {
            "type": "integer",
            "nullable": true
          },
          "fetchMs": {
            "type": "integer",
            "nullable": true
          },
          "results": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Per-page analysis (title, JSON-LD types, OG tags, canonical, headings, ...)"
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SiteAuditSummaryResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "RUNNING",
              "PAUSE_REQUESTED",
              "PAUSED",
              "CANCEL_REQUESTED",
              "CANCELLED",
              "COMPLETED",
              "FAILED"
            ]
          },
          "overallScore": {
            "type": "integer",
            "nullable": true
          },
          "categoryScores": {
            "$ref": "#/components/schemas/SiteAuditCategoryScores"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "SiteAuditDetailResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "targetDomain": {
            "type": "string",
            "description": "The domain this run actually audited — same value as `domain`, named for the any-target world."
          },
          "isOwnSite": {
            "type": "boolean",
            "description": "True when this run audited the project's configured website (as of start time). Own-site audits feed site search, recommendations and workflow data; external ones never do."
          },
          "selectedChecks": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/SiteAuditCheckId"
            },
            "description": "The check selection this run started with. Null = everything."
          },
          "status": {
            "type": "string",
            "enum": [
              "RUNNING",
              "PAUSE_REQUESTED",
              "PAUSED",
              "CANCEL_REQUESTED",
              "CANCELLED",
              "COMPLETED",
              "FAILED"
            ]
          },
          "progress": {
            "$ref": "#/components/schemas/SiteAuditProgress"
          },
          "overallScore": {
            "type": "integer",
            "nullable": true
          },
          "categoryScores": {
            "$ref": "#/components/schemas/SiteAuditCategoryScores"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditCheckResponse"
            }
          },
          "summary": {
            "$ref": "#/components/schemas/SiteAuditSummaryStats"
          },
          "pages": {
            "type": "array",
            "description": "The first 50 crawled pages only. Superseded by the paginated pages resource — an audit can now crawl thousands of pages, which cannot travel inline. Kept populated so a dashboard deployed against an older contract keeps working.",
            "items": {
              "$ref": "#/components/schemas/SiteAuditPageResponse"
            }
          },
          "share": {
            "allOf": [
              {
                "$ref": "#/components/schemas/SiteAuditShareResponse"
              }
            ],
            "nullable": true
          },
          "extras": {
            "type": "array",
            "description": "The follow-up lanes that join the report after the crawl (page speed, AI analysis). They never delay `status: COMPLETED` — a reader that sees a lane PENDING or RUNNING should keep polling and say \"still measuring\" instead of treating the data as absent.",
            "items": {
              "$ref": "#/components/schemas/SiteAuditExtraLane"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "SiteAuditExtraLane": {
        "type": "object",
        "description": "One follow-up lane of an audit run and where it stands.",
        "properties": {
          "lane": {
            "type": "string",
            "enum": [
              "PAGE_SPEED",
              "AI_ANALYSIS"
            ]
          },
          "status": {
            "type": "string",
            "description": "PENDING — the crawl hasn't finished, so the lane hasn't started. RUNNING — the lane is measuring now; its results slot into the report when it lands. SKIPPED — this run will not produce the lane (deselected at start, no provider configured, budget exhausted, nothing to measure, or cancelled).",
            "enum": [
              "PENDING",
              "RUNNING",
              "COMPLETED",
              "FAILED",
              "SKIPPED"
            ]
          }
        },
        "required": [
          "lane",
          "status"
        ]
      },
      "SiteAuditStartRequest": {
        "type": "object",
        "description": "Run options. The whole body is optional; omitting it runs with the service defaults.",
        "properties": {
          "maxPages": {
            "type": "integer",
            "nullable": true,
            "description": "How many pages the crawl may fetch. Bounded by the service's own floor and ceiling; a value outside them is rejected."
          },
          "followLinks": {
            "type": "boolean",
            "nullable": true,
            "description": "Follow internal links as well as the sitemap. False audits only what the sitemap lists, which is faster and blind to anything unlisted."
          },
          "targetUrl": {
            "type": "string",
            "nullable": true,
            "description": "Any http(s) address to audit. Omitted = the project's configured website domain. The address is reduced to its domain — a path or query is discarded, and IP literals, ports and credentials are rejected. Auditing a site other than the project's own counts against a daily allowance."
          },
          "checks": {
            "type": "array",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/SiteAuditCheckId"
            },
            "description": "Which checks to run. Omitted or null = all of them (the start dialog shows everything pre-checked). Core crawl steps run regardless. Deselected checks appear in the report as \"skipped — not selected for this run\"."
          }
        }
      },
      "SiteAuditSummaryStats": {
        "type": "object",
        "description": "The report's headline row, computed server-side. Every count here is produced after the caller's permission filter, so a hidden producer cannot be inferred from a total.",
        "properties": {
          "pagesCrawled": {
            "type": "integer"
          },
          "pagesDiscovered": {
            "type": "integer",
            "description": "URLs admitted to the crawl frontier, crawled or not yet."
          },
          "maxPages": {
            "type": "integer",
            "nullable": true
          },
          "frontierTruncated": {
            "type": "boolean",
            "description": "The crawl hit its page cap and stopped admitting URLs."
          },
          "followLinks": {
            "type": "boolean"
          },
          "issuesFound": {
            "type": "integer"
          },
          "severityCounts": {
            "$ref": "#/components/schemas/SiteAuditSeverityCounts"
          },
          "avgResponseMs": {
            "type": "integer",
            "nullable": true,
            "description": "Mean over the pages that answered. Pages that never responded are excluded rather than counted as zero."
          },
          "blockedPages": {
            "type": "integer",
            "description": "Pages bot protection turned the crawler away from."
          },
          "brokenPages": {
            "type": "integer"
          },
          "serverErrorPages": {
            "type": "integer"
          },
          "overallScore": {
            "type": "integer",
            "nullable": true
          },
          "categoryScores": {
            "$ref": "#/components/schemas/SiteAuditCategoryScores"
          },
          "availableSections": {
            "type": "array",
            "description": "Which finding producers this report draws on. Every producer is readable under siteaudit.view.",
            "items": {
              "type": "string",
              "enum": [
                "CRAWL",
                "CHECKLIST",
                "PAGE_CHECK",
                "SITE_CHECK",
                "CONTENT_CHECK"
              ]
            }
          },
          "lighthouseTests": {
            "type": "integer",
            "description": "Lighthouse measurements recorded for this audit, successes and failures together. Zero means no measurement run happened — no provider is configured, the audit predates Lighthouse, or the run is still going. The dashboard hides the four tiles below when this is zero rather than showing four empty ones."
          },
          "lighthouseFailures": {
            "type": "integer",
            "description": "Measurements the provider could not complete."
          },
          "avgLighthousePerformance": {
            "type": "integer",
            "nullable": true,
            "description": "Mean over the measurements that produced a score. Failed runs are excluded rather than counted as zero."
          },
          "avgLighthouseSeo": {
            "type": "integer",
            "nullable": true
          },
          "avgLighthouseAccessibility": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "SiteAuditSeverityCounts": {
        "type": "object",
        "properties": {
          "critical": {
            "type": "integer"
          },
          "warning": {
            "type": "integer"
          },
          "info": {
            "type": "integer"
          }
        }
      },
      "SiteAuditFindingGroup": {
        "type": "object",
        "description": "One rule, and how much of the site it affects. `source` and `findingId` together are the identity — ids collide across the catalogs, so a drill-down that sends only `findingId` is ambiguous.",
        "required": [
          "source",
          "findingId",
          "severity",
          "scope",
          "title",
          "description",
          "fix"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": [
              "CRAWL",
              "CHECKLIST",
              "PAGE_CHECK",
              "SITE_CHECK",
              "CONTENT_CHECK"
            ]
          },
          "findingId": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "CRITICAL",
              "WARNING",
              "INFO"
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "PAGE",
              "SITE"
            ]
          },
          "title": {
            "type": "string",
            "description": "What is wrong, as a short noun phrase"
          },
          "description": {
            "type": "string",
            "description": "Why it matters — the same sentence whichever page it is"
          },
          "fix": {
            "type": "string",
            "description": "What to do about it"
          },
          "affectedPages": {
            "type": "integer",
            "description": "Distinct pages carrying this finding; 0 for a site-wide one."
          },
          "findingCount": {
            "type": "integer"
          }
        }
      },
      "SiteAuditFindingResponse": {
        "type": "object",
        "description": "One finding on one page.",
        "required": [
          "source",
          "findingId",
          "severity",
          "scope",
          "title",
          "description",
          "fix"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": [
              "CRAWL",
              "CHECKLIST",
              "PAGE_CHECK",
              "SITE_CHECK",
              "CONTENT_CHECK"
            ]
          },
          "findingId": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "CRITICAL",
              "WARNING",
              "INFO"
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "PAGE",
              "SITE"
            ]
          },
          "pageUrl": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "detail": {
            "type": "string",
            "nullable": true,
            "description": "What this page measured, in a sentence."
          },
          "fix": {
            "type": "string"
          },
          "details": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Structured evidence (the chain, the duplicate group, the linking pages)"
          }
        }
      },
      "PaginatedSiteAuditFindings": {
        "type": "object",
        "description": "Paginated findings for one audit",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditFindingResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "SiteAuditPageRow": {
        "type": "object",
        "description": "One crawled page, as the Pages tab shows it.",
        "properties": {
          "id": {
            "type": "string",
            "description": "This crawl's row for the page — what the page-detail resource is addressed by. Belongs to one audit; the same URL crawled again has a different id."
          },
          "url": {
            "type": "string"
          },
          "finalUrl": {
            "type": "string",
            "nullable": true
          },
          "statusCode": {
            "type": "integer",
            "nullable": true
          },
          "fetchClass": {
            "type": "string",
            "nullable": true,
            "enum": [
              "OK",
              "REDIRECT",
              "BROKEN",
              "SERVER_ERROR",
              "BLOCKED",
              "ERROR"
            ]
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "h1Count": {
            "type": "integer",
            "nullable": true
          },
          "wordCount": {
            "type": "integer",
            "nullable": true
          },
          "imagesTotal": {
            "type": "integer",
            "nullable": true
          },
          "imagesMissingAlt": {
            "type": "integer",
            "nullable": true
          },
          "internalLinkCount": {
            "type": "integer",
            "nullable": true
          },
          "responseTimeMs": {
            "type": "integer",
            "nullable": true
          },
          "crawlDepth": {
            "type": "integer",
            "nullable": true,
            "description": "Clicks from the homepage; null for a page seeded from the sitemap."
          },
          "inSitemap": {
            "type": "boolean"
          },
          "indexable": {
            "type": "boolean",
            "nullable": true
          },
          "source": {
            "type": "string",
            "enum": [
              "HOMEPAGE",
              "SITEMAP",
              "LINK"
            ]
          },
          "issueCount": {
            "type": "integer"
          }
        }
      },
      "PaginatedSiteAuditPages": {
        "type": "object",
        "description": "Paginated crawled pages for one audit",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditPageRow"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "SiteAuditRecentPage": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "statusCode": {
            "type": "integer",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "crawledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "SiteAuditProgressResponse": {
        "type": "object",
        "description": "Live progress while an audit runs.",
        "properties": {
          "phase": {
            "type": "string",
            "description": "LIGHTHOUSE and ANALYZING both mean the crawl is finished and the report is readable — the page-speed measurement (then the AI analysis) is still filling in. Only DONE means nothing is left to watch, so poll until DONE, not until the audit's status settles.",
            "enum": [
              "DISCOVERY",
              "CRAWLING",
              "FINALIZING",
              "LIGHTHOUSE",
              "ANALYZING",
              "DONE"
            ]
          },
          "pagesCrawled": {
            "type": "integer"
          },
          "pagesDiscovered": {
            "type": "integer"
          },
          "totalUnits": {
            "type": "integer"
          },
          "completedUnits": {
            "type": "integer"
          },
          "failedUnits": {
            "type": "integer"
          },
          "lighthouseTotal": {
            "type": "integer",
            "description": "Measurements the downstream Lighthouse job will make, 0 when no run was started. During the LIGHTHOUSE phase the progress bar counts these instead of crawl units."
          },
          "lighthouseCompleted": {
            "type": "integer"
          },
          "recentPages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditRecentPage"
            }
          }
        }
      },
      "SiteAuditLighthouseRow": {
        "type": "object",
        "description": "One Lighthouse measurement of one page on one device. Scores are 0-100; every score is null when `errorMessage` is set.",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "device": {
            "type": "string",
            "enum": [
              "MOBILE",
              "DESKTOP"
            ]
          },
          "performanceScore": {
            "type": "integer",
            "nullable": true
          },
          "accessibilityScore": {
            "type": "integer",
            "nullable": true
          },
          "seoScore": {
            "type": "integer",
            "nullable": true
          },
          "bestPracticesScore": {
            "type": "integer",
            "nullable": true
          },
          "lcpMs": {
            "type": "integer",
            "nullable": true,
            "description": "Largest Contentful Paint."
          },
          "fcpMs": {
            "type": "integer",
            "nullable": true,
            "description": "First Contentful Paint."
          },
          "cls": {
            "type": "number",
            "nullable": true,
            "description": "Cumulative Layout Shift; unitless."
          },
          "tbtMs": {
            "type": "integer",
            "nullable": true,
            "description": "Total Blocking Time — the lab stand-in for INP. INP itself is a field metric that a lab run cannot measure, so it is not reported."
          },
          "ttfbMs": {
            "type": "integer",
            "nullable": true,
            "description": "Server response time."
          },
          "speedIndexMs": {
            "type": "integer",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true,
            "description": "Set when the provider could not measure the page."
          },
          "measuredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "PaginatedSiteAuditLighthouse": {
        "type": "object",
        "description": "Paginated Lighthouse measurements for one audit",
        "required": [
          "data",
          "page",
          "size",
          "totalElements",
          "totalPages"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditLighthouseRow"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          }
        }
      },
      "SiteAuditPageCheck": {
        "type": "object",
        "description": "One page-checklist verdict on one page, with the copy that explains it. Only the checks that did not pass are recorded, so `status` is FAIL or WARNING in practice — a page with nothing wrong carries no rows here rather than thirty passing ones.",
        "required": [
          "checkId",
          "status",
          "title",
          "description",
          "fix"
        ],
        "properties": {
          "checkId": {
            "type": "string",
            "description": "The rule's id, as list_site_audit_issues and the findings resource report it."
          },
          "status": {
            "type": "string",
            "enum": [
              "PASS",
              "FAIL",
              "WARNING",
              "INFO"
            ]
          },
          "title": {
            "type": "string",
            "description": "What the check is, phrased as the good outcome"
          },
          "description": {
            "type": "string",
            "description": "Why it matters — the same sentence whichever page it is"
          },
          "detail": {
            "type": "string",
            "nullable": true,
            "description": "What this page measured, in a sentence. Null for rules whose evidence this release cannot re-read into a shape; `evidence` still carries the measurement."
          },
          "fix": {
            "type": "string"
          },
          "evidence": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "The measurement the check recorded, as it was stored."
          }
        }
      },
      "SiteAuditPageAiRead": {
        "type": "object",
        "description": "What a model made of this page, pinned to the crawl whose copy it read. Absent when the audit ran without the AI lane, or when this page was not one of the pages it read.",
        "properties": {
          "buyerQuestion": {
            "type": "string",
            "nullable": true,
            "description": "The question a buyer arrives with that this page answers."
          },
          "presentsItselfAs": {
            "type": "string",
            "nullable": true,
            "description": "What the page says it is, in its own terms."
          },
          "positioning": {
            "type": "string",
            "nullable": true,
            "description": "How the page sits against what the rest of the site claims."
          },
          "recommendation": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SiteAuditSimilarPage": {
        "type": "object",
        "description": "One page near this one, and how near.",
        "required": [
          "pageId",
          "url",
          "score"
        ],
        "properties": {
          "pageId": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "score": {
            "type": "number",
            "description": "Cosine similarity, 0..1. 1 is the same copy."
          }
        }
      },
      "SiteAuditPageTrafficPoint": {
        "type": "object",
        "required": [
          "day",
          "views",
          "aiHits"
        ],
        "properties": {
          "day": {
            "type": "string",
            "format": "date"
          },
          "views": {
            "type": "integer",
            "description": "Human page views recorded for the path that day."
          },
          "aiHits": {
            "type": "integer",
            "description": "AI-crawler requests recorded for the path that day."
          }
        }
      },
      "SiteAuditPageTrafficResponse": {
        "type": "object",
        "description": "The page's recent audience, human and machine, day by day. Zero-filled days are omitted; the window says how far back the series looks.",
        "required": [
          "windowDays",
          "points"
        ],
        "properties": {
          "windowDays": {
            "type": "integer"
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditPageTrafficPoint"
            }
          }
        }
      },
      "SiteAuditPageDetailResponse": {
        "type": "object",
        "description": "Everything one crawl knows about one page: the facts it measured, the checklist verdicts it recorded, what a model made of the copy, and the pages nearest to it. The retained markup is deliberately not part of this — it is an input to the checks, not a report.",
        "required": [
          "id",
          "url",
          "inSitemap",
          "findingsCount",
          "checks",
          "similarPages"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "finalUrl": {
            "type": "string",
            "nullable": true,
            "description": "Where the fetch ended up, when it was redirected."
          },
          "statusCode": {
            "type": "integer",
            "nullable": true
          },
          "fetchClass": {
            "type": "string",
            "nullable": true,
            "enum": [
              "OK",
              "REDIRECT",
              "BROKEN",
              "SERVER_ERROR",
              "BLOCKED",
              "ERROR"
            ]
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "metaDescription": {
            "type": "string",
            "nullable": true
          },
          "canonicalUrl": {
            "type": "string",
            "nullable": true
          },
          "h1Count": {
            "type": "integer",
            "nullable": true
          },
          "headingCount": {
            "type": "integer",
            "nullable": true
          },
          "wordCount": {
            "type": "integer",
            "nullable": true
          },
          "imagesTotal": {
            "type": "integer",
            "nullable": true
          },
          "imagesMissingAlt": {
            "type": "integer",
            "nullable": true
          },
          "internalLinkCount": {
            "type": "integer",
            "nullable": true
          },
          "externalLinkCount": {
            "type": "integer",
            "nullable": true
          },
          "contentBytes": {
            "type": "integer",
            "nullable": true
          },
          "fetchMs": {
            "type": "integer",
            "nullable": true,
            "description": "How long the whole fetch took, including redirects."
          },
          "responseTimeMs": {
            "type": "integer",
            "nullable": true,
            "description": "How long the terminal response took, which is what the site is judged on."
          },
          "crawlDepth": {
            "type": "integer",
            "nullable": true,
            "description": "Clicks from the homepage; null for a page seeded from the sitemap."
          },
          "inSitemap": {
            "type": "boolean"
          },
          "indexable": {
            "type": "boolean",
            "nullable": true
          },
          "discoverySource": {
            "type": "string",
            "enum": [
              "HOMEPAGE",
              "SITEMAP",
              "LINK"
            ],
            "description": "How the crawl first reached this page."
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When an own-site audit first saw this address. Carried forward between runs, so it predates this audit; null for a page with no earlier snapshot to carry from."
          },
          "lastChangedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the page's content last differed from the previous run's."
          },
          "crawledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "findingsCount": {
            "type": "integer",
            "description": "Findings of every producer attached to this page, after the caller's permission filter — so it can exceed the length of `checks`, which is only the page checklist."
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditPageCheck"
            },
            "description": "This page's checklist verdicts. Empty when the audit ran no page checks, which is not the same as the page having passed everything."
          },
          "aiRead": {
            "allOf": [
              {
                "$ref": "#/components/schemas/SiteAuditPageAiRead"
              }
            ],
            "nullable": true
          },
          "similarPages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditSimilarPage"
            },
            "description": "Nearest pages by meaning, best first. Empty when the audit ran without the similarity pass, or when nothing scored above the naming threshold."
          }
        }
      },
      "SiteAuditClusterPage": {
        "type": "object",
        "required": [
          "pageId",
          "url"
        ],
        "properties": {
          "pageId": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SiteAuditSimilarityCluster": {
        "type": "object",
        "description": "A group of pages that are all reachable from each other above the threshold — one problem with several pages in it, not several pairs.",
        "required": [
          "pages",
          "score",
          "verdict"
        ],
        "properties": {
          "pages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditClusterPage"
            }
          },
          "score": {
            "type": "number",
            "description": "The tightest link inside the cluster, 0..1."
          },
          "verdict": {
            "type": "string",
            "enum": [
              "NEAR_DUPLICATE",
              "RELATED"
            ],
            "description": "NEAR_DUPLICATE when the tightest link is at or above the near-duplicate threshold — two pages that are nearly the same page. RELATED is normal for a site that covers one subject and is reported so a reader can see what the grouping is made of."
          }
        }
      },
      "SiteAuditSimilarityResponse": {
        "type": "object",
        "description": "What the audit's embeddings say about duplication. Empty clusters with a zero `pagesCompared` means the similarity pass did not run — no embeddings model, or the run predates it.",
        "required": [
          "clusters",
          "pagesCompared",
          "pagesInClusters",
          "nearDuplicateClusters",
          "relatedClusters"
        ],
        "properties": {
          "clusters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditSimilarityCluster"
            },
            "description": "Tightest first."
          },
          "pagesCompared": {
            "type": "integer",
            "description": "Pages that carried a vector and so took part in the ranking at all."
          },
          "pagesInClusters": {
            "type": "integer",
            "description": "Pages that landed in a cluster of two or more."
          },
          "nearDuplicateClusters": {
            "type": "integer"
          },
          "relatedClusters": {
            "type": "integer"
          }
        }
      },
      "SiteAuditAffectedPage": {
        "type": "object",
        "description": "One page a site check names, and what is true of it.",
        "required": [
          "path"
        ],
        "properties": {
          "path": {
            "type": "string"
          },
          "note": {
            "type": "string",
            "nullable": true,
            "description": "What is true of this page in a few words; null when naming the page says everything."
          }
        }
      },
      "SiteAuditSiteCheckRow": {
        "type": "object",
        "description": "One graded site-wide check, passes included. `source` and `checkId` together are the identity — the ids collide across catalogs.",
        "required": [
          "source",
          "checkId",
          "severity",
          "title",
          "description",
          "fix"
        ],
        "properties": {
          "source": {
            "type": "string",
            "enum": [
              "CRAWL",
              "CHECKLIST",
              "PAGE_CHECK",
              "SITE_CHECK",
              "CONTENT_CHECK"
            ]
          },
          "checkId": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "BROKEN",
              "WARNING",
              "WORKS"
            ],
            "description": "WORKS is the check holding up — this resource is the only one that reports it."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "detail": {
            "type": "string",
            "nullable": true,
            "description": "What this run measured, in the check's own words."
          },
          "fix": {
            "type": "string"
          },
          "affectedPages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditAffectedPage"
            },
            "description": "The pages the check names. Empty when the finding is a count or a comparison rather than a set of pages."
          }
        }
      },
      "SiteAuditFactsResponse": {
        "type": "object",
        "description": "The whole graded checklist for one audit, including the checks that hold up. The findings resources are structurally issues-only — a finding exists because something is wrong — so this is the only place that can say how many checks ran.",
        "required": [
          "checks",
          "checksRun"
        ],
        "properties": {
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SiteAuditSiteCheckRow"
            },
            "description": "Worst first."
          },
          "checksRun": {
            "type": "integer",
            "description": "The denominator — how many checks this audit graded at all."
          }
        }
      },
      "SiteAuditShareResponse": {
        "type": "object",
        "description": "A public link to one finished audit. Carried on the audit detail response as `share` — null there when the audit has never been shared or the link was revoked — so the report can re-show a link that already exists rather than minting a second one.",
        "required": [
          "token",
          "url",
          "createdAt"
        ],
        "properties": {
          "token": {
            "type": "string",
            "description": "The whole credential. Anyone holding it can read the redacted report, so it is shown rather than hashed, and revoking is how it is turned off."
          },
          "url": {
            "type": "string",
            "description": "The link to hand somebody, built from the dashboard's own base URL."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AiVisibilitySeriesPoint": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time"
          },
          "presenceRate": {
            "type": "number",
            "description": "runsWithBrand / runCount, 0..1"
          },
          "runCount": {
            "type": "integer"
          },
          "runsWithBrand": {
            "type": "integer"
          },
          "citationCount": {
            "type": "integer"
          },
          "selfCitationCount": {
            "type": "integer"
          },
          "runsWithMention": {
            "type": "integer",
            "nullable": true,
            "description": "Runs whose answer mentioned the brand; null when the job predates analysis"
          },
          "runsWithCitation": {
            "type": "integer",
            "nullable": true,
            "description": "Runs that cited the brand's domain; null when the job predates analysis"
          },
          "mentionRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithMention / runCount, 0..1; null when not analyzed"
          },
          "citationRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithCitation / runCount, 0..1; null when not analyzed"
          }
        }
      },
      "AiVisibilitySeriesResponse": {
        "type": "object",
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            },
            "description": "The engine selection this response was computed for (empty = every engine)"
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilitySeriesPoint"
            }
          },
          "comparisonSeries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilitySeriesPoint"
            },
            "description": "The same series read over the comparison window, under the same engine, topic\nand region filters. Present unless the read answers by job count.\n\nIts points are that window's own jobs, carrying their own ids and finish\ntimes, so a chart lines the two up by position rather than by date — the two\nwindows rarely run the same number of scans, and no job here has a\ncounterpart there. The citations page's headline figures are sums over these\npoints (total citations, own citations, citations per answer), so the earlier\nfigures are the same sums over this array.\n"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityDomainEntry": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string"
          },
          "citationCount": {
            "type": "integer"
          },
          "citationShare": {
            "type": "number",
            "nullable": true,
            "description": "This domain's share of the citations the selected period recorded, 0..1. The denominator is every citation across every domain the window cited — not only the domains on this page — which is the same denominator previousCitationShare is taken against, so the two are comparable. Null when the window recorded no citations at all: a domain cannot hold a share of nothing, and 0 would claim it was measured and found absent.\n"
          },
          "classification": {
            "type": "string",
            "enum": [
              "SELF",
              "COMPETITOR",
              "OTHER"
            ]
          },
          "sourceType": {
            "type": "string",
            "nullable": true,
            "description": "Static source-type sub-classification; null when the job predates it",
            "enum": [
              "VENDOR",
              "UGC",
              "REVIEW_SITE",
              "REFERENCE",
              "NEWS",
              "SOCIAL",
              "DOCS",
              "MARKETPLACE",
              "EDITORIAL"
            ]
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI engines that cited this domain at least once in the aggregated jobs, scoped to the provider filter ('ALL' lists every engine)"
          },
          "marketplaceSiteId": {
            "type": "string",
            "nullable": true,
            "description": "Set when this cited domain is purchasable as a guest-post placement in the marketplace — deep-links to the catalog. Null when the marketplace is disabled or does not carry the domain."
          },
          "purchasableFromCents": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Cheapest retail placement price on this domain in USD cents; null when not purchasable"
          },
          "previousCitationCount": {
            "type": "integer",
            "description": "Citations this domain received in the comparison window, under the same engine, topic and region filters. Present unless the read answers by job count; 0 when that window cited the domain not at all.\n"
          },
          "previousCitationShare": {
            "type": "number",
            "nullable": true,
            "description": "This domain's share of every citation the comparison window recorded, 0..1 — 0 when that window cited other domains but never this one, which is a measured zero. Null means there is nothing to take a share of: the window recorded no citations at all, so this domain was never measured there rather than measured at nothing.\n"
          },
          "absoluteChange": {
            "type": "integer",
            "description": "citationCount - previousCitationCount. Citations are what the map ranks on, so the change fields describe them. Present unless the read answers by job count.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Relative change from previousCitationCount to citationCount. Null when previousCitationCount is 0 — there is no percentage that describes going from nothing to something.\n"
          }
        }
      },
      "AiVisibilityDomainsResponse": {
        "type": "object",
        "description": "The cited-domain map as the selected period ranks it. Which domains appear, and in\nwhich order, is decided by that period alone — a domain cited only in the\ncomparison window is not listed on a page about who is being cited now, and each\nlisted domain's earlier figures are looked up by its own name rather than read off\nwhatever occupied its position back then.\n",
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            },
            "description": "The engine selection this response was computed for (empty = every engine)"
          },
          "jobsIncluded": {
            "type": "integer",
            "description": "Number of completed jobs aggregated"
          },
          "comparisonJobsIncluded": {
            "type": "integer",
            "description": "Completed jobs the comparison figures were read from, counted the same way as jobsIncluded. Present unless the read answers by job count. 0 says the project ran no analysis in that window at all — which is why every previous figure is zero and every previous share is null — as opposed to having run and cited nobody.\n"
          },
          "domains": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityDomainEntry"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityDomainCitationUrl": {
        "type": "object",
        "description": "One distinct cited URL under a domain, with how many times it was cited",
        "required": [
          "citationCount"
        ],
        "properties": {
          "rawUrl": {
            "type": "string",
            "nullable": true,
            "description": "The full cited URL as returned by the engine; null when normalization dropped it"
          },
          "urlPath": {
            "type": "string",
            "nullable": true,
            "description": "Path portion of the URL"
          },
          "title": {
            "type": "string",
            "nullable": true,
            "description": "Page title reported alongside the citation, if any"
          },
          "citationCount": {
            "type": "integer",
            "description": "Number of citations to this exact URL across the aggregated jobs"
          }
        }
      },
      "AiVisibilityDomainCitationsResponse": {
        "type": "object",
        "description": "Basic info about one cited domain plus a paginated list of the actual cited URLs",
        "properties": {
          "domain": {
            "type": "string"
          },
          "classification": {
            "type": "string",
            "nullable": true,
            "enum": [
              "SELF",
              "COMPETITOR",
              "OTHER"
            ]
          },
          "sourceType": {
            "type": "string",
            "nullable": true,
            "enum": [
              "VENDOR",
              "UGC",
              "REVIEW_SITE",
              "REFERENCE",
              "NEWS",
              "SOCIAL",
              "DOCS",
              "MARKETPLACE",
              "EDITORIAL"
            ]
          },
          "totalCitations": {
            "type": "integer",
            "description": "Total citations to this domain across the aggregated jobs (for the selected provider)"
          },
          "distinctUrls": {
            "type": "integer",
            "description": "Number of distinct cited URLs under this domain"
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI engines that cited this domain at least once in the aggregated jobs, scoped to the provider filter ('ALL' lists every engine)"
          },
          "jobsIncluded": {
            "type": "integer",
            "description": "Number of completed jobs aggregated"
          },
          "marketplaceSiteId": {
            "type": "string",
            "nullable": true,
            "description": "Set when this domain is purchasable as a guest-post placement in the marketplace; null otherwise"
          },
          "purchasableFromCents": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Cheapest retail placement price on this domain in USD cents; null when not purchasable"
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          },
          "urls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityDomainCitationUrl"
            }
          }
        }
      },
      "AiVisibilityCitedPage": {
        "type": "object",
        "description": "One distinct cited page (URL) across all domains, with how many times it was cited",
        "required": [
          "rawUrl",
          "citationCount"
        ],
        "properties": {
          "rawUrl": {
            "type": "string",
            "description": "The full cited URL as returned by the engine"
          },
          "domain": {
            "type": "string",
            "nullable": true,
            "description": "Registrable domain (eTLD+1) of the page; null when normalization failed"
          },
          "urlPath": {
            "type": "string",
            "nullable": true,
            "description": "Path portion of the URL"
          },
          "title": {
            "type": "string",
            "nullable": true,
            "description": "Page title reported alongside the citation, if any"
          },
          "classification": {
            "type": "string",
            "nullable": true,
            "enum": [
              "SELF",
              "COMPETITOR",
              "OTHER"
            ],
            "description": "Classification of the page's domain against the tracked brand set"
          },
          "sourceType": {
            "type": "string",
            "nullable": true,
            "enum": [
              "VENDOR",
              "UGC",
              "REVIEW_SITE",
              "REFERENCE",
              "NEWS",
              "SOCIAL",
              "DOCS",
              "MARKETPLACE",
              "EDITORIAL"
            ]
          },
          "citationCount": {
            "type": "integer",
            "description": "Number of citations to this exact URL across the aggregated jobs"
          },
          "citationShare": {
            "type": "number",
            "nullable": true,
            "description": "This page's share of the citations the selected period recorded, 0..1. The denominator is every citation the window holds across all cited pages — not only the ones on this page of results — which is the same denominator previousCitationShare is taken against, so the two are comparable. Null when the window recorded no citations at all.\n"
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI engines that cited this page at least once, scoped to the provider filter ('ALL' lists every engine)"
          },
          "previousCitationCount": {
            "type": "integer",
            "description": "Citations this exact URL received in the comparison window, under the same engine, topic, region and mentioningBrand filters. Present unless the read answers by job count; 0 when that window cited the page not at all.\n"
          },
          "previousCitationShare": {
            "type": "number",
            "nullable": true,
            "description": "This page's share of every citation the comparison window recorded, 0..1 — 0 when that window cited other pages but never this one, which is a measured zero. Null means there is nothing to take a share of: the window recorded no citations at all, so this page was never measured there rather than measured at nothing.\n"
          },
          "absoluteChange": {
            "type": "integer",
            "description": "citationCount - previousCitationCount. Citations are what the list ranks on, so the change fields describe them. Present unless the read answers by job count.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Relative change from previousCitationCount to citationCount. Null when previousCitationCount is 0 — there is no percentage that describes going from nothing to something.\n"
          }
        }
      },
      "AiVisibilityCitedPagesResponse": {
        "type": "object",
        "description": "Paginated flat list of the pages AI engines cited, across all domains. Which pages\nappear, and on which page of the list, is decided by the selected period alone — a\nURL cited only in the comparison window is not listed — and each listed page's\nearlier figures are looked up by its own URL rather than read off whatever\noccupied its position back then.\n",
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            },
            "description": "The engine selection this response was computed for (empty = every engine)"
          },
          "mentioningBrand": {
            "type": "boolean",
            "description": "Echo of the request filter — true when only citations from answers featuring the project's own brand are counted"
          },
          "jobsIncluded": {
            "type": "integer",
            "description": "Number of completed jobs aggregated"
          },
          "comparisonJobsIncluded": {
            "type": "integer",
            "description": "Completed jobs the comparison figures were read from, counted the same way as jobsIncluded. Present unless the read answers by job count. 0 says the project ran no analysis in that window at all — which is why every previous figure is zero and every previous share is null — as opposed to having run and cited nothing.\n"
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "totalElements": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          },
          "pages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityCitedPage"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityBreakdownEntry": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string"
          },
          "runCount": {
            "type": "integer"
          },
          "runsWithBrand": {
            "type": "integer"
          },
          "presenceRate": {
            "type": "number"
          },
          "citationCount": {
            "type": "integer"
          },
          "selfCitationCount": {
            "type": "integer"
          },
          "runsWithMention": {
            "type": "integer",
            "nullable": true
          },
          "runsWithCitation": {
            "type": "integer",
            "nullable": true
          },
          "recommendedCount": {
            "type": "integer",
            "nullable": true
          },
          "sentimentPositiveCount": {
            "type": "integer",
            "nullable": true
          },
          "sentimentNeutralCount": {
            "type": "integer",
            "nullable": true
          },
          "sentimentNegativeCount": {
            "type": "integer",
            "nullable": true
          },
          "answerRankSum": {
            "type": "integer",
            "nullable": true
          },
          "answerRankCount": {
            "type": "integer",
            "nullable": true
          },
          "rankFirstCount": {
            "type": "integer",
            "nullable": true
          },
          "rankTop3Count": {
            "type": "integer",
            "nullable": true
          },
          "mentionRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithMention / runs in analyzed jobs; null when not analyzed"
          },
          "citationRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithCitation / runs in analyzed jobs; null when not analyzed"
          },
          "recommendedRate": {
            "type": "number",
            "nullable": true,
            "description": "recommendedCount / sentiment-classified mentions; null when not analyzed"
          },
          "avgAnswerRank": {
            "type": "number",
            "nullable": true,
            "description": "answerRankSum / answerRankCount; null when no ranked answers"
          },
          "previousRunCount": {
            "type": "integer",
            "description": "Runs this engine answered in the comparison window, under the same topic and region filters. Present unless the read answers by job count; 0 when the engine did not run then.\n"
          },
          "previousRunsWithBrand": {
            "type": "integer",
            "description": "Runs of this engine the brand was present in during the comparison window. Present unless the read answers by job count.\n"
          },
          "previousPresenceRate": {
            "type": "number",
            "description": "previousRunsWithBrand / previousRunCount, 0..1 — 0 when the engine did not run in the comparison window. Present unless the read answers by job count.\n"
          },
          "previousCitationCount": {
            "type": "integer",
            "description": "Citations this engine's answers carried in the comparison window. Present unless the read answers by job count."
          },
          "previousSelfCitationCount": {
            "type": "integer",
            "description": "How many of those comparison-window citations pointed at the project's own domains. Paired with previousCitationCount it gives the earlier window's self-citation share, which is what the citation meter compares against. Present unless the read answers by job count.\n"
          },
          "previousMentionRate": {
            "type": "number",
            "nullable": true,
            "description": "Mention rate over the comparison window; null when nothing was analyzed then."
          },
          "previousCitationRate": {
            "type": "number",
            "nullable": true,
            "description": "Domain-citation rate over the comparison window; null when nothing was analyzed then."
          },
          "previousAvgAnswerRank": {
            "type": "number",
            "nullable": true,
            "description": "Average answer rank over the comparison window. Null — never 0 — when the engine ranked no answers then: 0 is the best position there is, not absence.\n"
          },
          "absoluteChange": {
            "type": "number",
            "format": "double",
            "description": "Change in presenceRate, in percentage points (presenceRate is the engine's headline metric, so the change fields describe it). A rate of 0.4286 against 0.2857 reads as 14.3 — the difference between the two figures as the page shows them. Present unless the read answers by job count.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Relative change from previousPresenceRate to presenceRate. Null when previousPresenceRate is 0.\n"
          }
        }
      },
      "AiVisibilityBreakdownResponse": {
        "type": "object",
        "properties": {
          "jobsIncluded": {
            "type": "integer"
          },
          "comparisonJobsIncluded": {
            "type": "integer",
            "description": "Completed jobs the comparison figures were read from. Present unless the read answers by job count. 0 says the project ran no analysis in that window at all — which is why every previous figure is zero — as opposed to having run and found nothing.\n"
          },
          "byProvider": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityBreakdownEntry"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityCompetitorEntry": {
        "type": "object",
        "properties": {
          "brandId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "isSelf": {
            "type": "boolean"
          },
          "primaryDomain": {
            "type": "string",
            "nullable": true
          },
          "rank": {
            "type": "integer",
            "description": "1-based leaderboard position, ordered by visibility rate descending"
          },
          "visibilityRate": {
            "type": "number",
            "description": "runsWithBrand / runCount across the aggregated jobs, 0..1"
          },
          "citationCount": {
            "type": "integer"
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI engines that mentioned or cited this brand at least once in the aggregated jobs, scoped to the provider filter ('ALL' lists every engine)"
          },
          "shareOfVoice": {
            "type": "number",
            "nullable": true,
            "description": "This brand's runsWithBrand divided by the sum across all brands; null when no brand had any presence"
          },
          "mentionRate": {
            "type": "number",
            "nullable": true,
            "description": "Mention rate over the analyzed sub-window; null when not analyzed"
          },
          "citationRate": {
            "type": "number",
            "nullable": true,
            "description": "Domain-citation rate over the analyzed sub-window; null when not analyzed"
          },
          "recommendedRate": {
            "type": "number",
            "nullable": true,
            "description": "recommendedCount / sentiment-classified mentions; null when not analyzed"
          },
          "avgAnswerRank": {
            "type": "number",
            "nullable": true,
            "description": "answerRankSum / answerRankCount; null when no ranked answers"
          },
          "answerRankCount": {
            "type": "integer",
            "nullable": true
          },
          "rankFirstCount": {
            "type": "integer",
            "nullable": true
          },
          "rankTop3Count": {
            "type": "integer",
            "nullable": true
          },
          "sentimentPositiveCount": {
            "type": "integer",
            "nullable": true
          },
          "sentimentNeutralCount": {
            "type": "integer",
            "nullable": true
          },
          "sentimentNegativeCount": {
            "type": "integer",
            "nullable": true
          },
          "previousVisibilityRate": {
            "type": "number",
            "description": "This brand's visibility rate over the comparison window, 0..1, under the same engine, topic and region filters. Present unless the read answers by job count; 0 when the brand was not visible then.\n"
          },
          "previousRank": {
            "type": "integer",
            "nullable": true,
            "description": "Where this brand stood in the comparison window's leaderboard. Null — never a number — when the brand was not measured at all then, because a rank is a position: reporting it as last place would read as \"was bottom, now second\" for a brand that simply had no data.\n"
          },
          "previousShareOfVoice": {
            "type": "number",
            "nullable": true,
            "description": "This brand's share of voice over the comparison window; null when no brand had any presence then.\n"
          },
          "previousCitationCount": {
            "type": "integer",
            "description": "Citations this brand's domain received in the comparison window. Present unless the read answers by job count."
          },
          "previousAvgAnswerRank": {
            "type": "number",
            "nullable": true,
            "description": "Average answer rank over the comparison window. Null — never 0 — when the brand had no ranked answers then: 0 is the best position there is, not absence.\n"
          },
          "absoluteChange": {
            "type": "number",
            "format": "double",
            "description": "Change in visibilityRate, in percentage points (visibility is what the leaderboard ranks on, so the change fields describe it). A rate of 0.4286 against 0.2857 reads as 14.3. Present unless the read answers by job count.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Relative change from previousVisibilityRate to visibilityRate. Null when previousVisibilityRate is 0.\n"
          }
        }
      },
      "AiVisibilityCompetitorsResponse": {
        "type": "object",
        "description": "The leaderboard as the selected period ranks it. A brand's position, and whether\nit appears at all, is decided by that period alone — a competitor that was visible\nonly in the comparison window is not ranked into a picture of who is winning now.\n",
        "properties": {
          "jobsIncluded": {
            "type": "integer"
          },
          "comparisonJobsIncluded": {
            "type": "integer",
            "description": "Completed jobs the comparison figures were read from, counted the same way as jobsIncluded. Present unless the read answers by job count. 0 says the project ran no analysis in that window at all, which is why every previous figure is zero — as opposed to having run and found nobody.\n"
          },
          "competitors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityCompetitorEntry"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityDiscoveredCompetitorEntry": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Brand/product name as the AI wrote it (display casing)"
          },
          "primaryDomain": {
            "type": "string",
            "nullable": true,
            "description": "Best-effort registrable domain when the answer tied the brand to a website; null otherwise"
          },
          "mentionCount": {
            "type": "integer",
            "description": "Number of distinct runs in which the AI named this untracked brand"
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI engines that named this brand at least once, scoped to the provider filter ('ALL' lists every engine)"
          }
        }
      },
      "AiVisibilityDiscoveredCompetitorsResponse": {
        "type": "object",
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            },
            "description": "The engine selection this response was computed for (empty = every engine)"
          },
          "jobsIncluded": {
            "type": "integer"
          },
          "competitors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityDiscoveredCompetitorEntry"
            }
          }
        }
      },
      "AiVisibilityCitationEntry": {
        "type": "object",
        "properties": {
          "position": {
            "type": "integer"
          },
          "rawUrl": {
            "type": "string",
            "nullable": true
          },
          "normalizedDomain": {
            "type": "string",
            "nullable": true
          },
          "urlPath": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "snippet": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AiVisibilityMentionEntry": {
        "type": "object",
        "properties": {
          "brandId": {
            "type": "string"
          },
          "brandName": {
            "type": "string"
          },
          "mentionType": {
            "type": "string",
            "enum": [
              "SELF",
              "COMPETITOR"
            ]
          },
          "matchedAlias": {
            "type": "string",
            "nullable": true
          },
          "firstPosition": {
            "type": "integer",
            "nullable": true
          },
          "occurrenceCount": {
            "type": "integer"
          },
          "sentiment": {
            "type": "string",
            "nullable": true,
            "description": "LLM-classified sentiment; null when the run predates analysis or was unclassified",
            "enum": [
              "POSITIVE",
              "NEUTRAL",
              "NEGATIVE"
            ]
          },
          "recommended": {
            "type": "boolean",
            "nullable": true,
            "description": "Actively recommended (true) vs merely mentioned (false); null when unanalyzed"
          },
          "answerRank": {
            "type": "integer",
            "nullable": true,
            "description": "1-based rank within a ranked answer; null when not ranked or unanalyzed"
          },
          "listSize": {
            "type": "integer",
            "nullable": true,
            "description": "Number of options the answer presented; null when not a ranked answer or unanalyzed"
          }
        }
      },
      "AiVisibilityRunSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "region": {
            "$ref": "#/components/schemas/AiVisibilityRegionEnum"
          },
          "market": {
            "type": "string",
            "description": "ISO-3166 alpha-2 country this run actually queried (the region may cover several)"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "PROCESSING",
              "AWAITING_PROVIDER",
              "SUCCEEDED",
              "FAILED"
            ]
          },
          "promptId": {
            "type": "string",
            "nullable": true
          },
          "promptText": {
            "type": "string",
            "nullable": true
          },
          "topicId": {
            "type": "string",
            "nullable": true,
            "description": "Topic snapshotted on the run at execution/backfill time (null = uncategorized)"
          },
          "topicName": {
            "type": "string",
            "nullable": true,
            "description": "Resolved topic name (kept resolvable for archived topics)"
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "AiVisibilityRunDetailResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "region": {
            "$ref": "#/components/schemas/AiVisibilityRegionEnum"
          },
          "market": {
            "type": "string",
            "description": "ISO-3166 alpha-2 country this run actually queried (the region may cover several)"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "PROCESSING",
              "AWAITING_PROVIDER",
              "SUCCEEDED",
              "FAILED"
            ]
          },
          "modelVersion": {
            "type": "string",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true
          },
          "promptText": {
            "type": "string",
            "nullable": true
          },
          "answerText": {
            "type": "string",
            "nullable": true
          },
          "citations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityCitationEntry"
            }
          },
          "mentions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityMentionEntry"
            }
          },
          "paidPlacements": {
            "type": "array",
            "description": "Advertisements shown inside this answer, including any the engine was served but never displayed (see `isRendered`). Always empty for engines whose answers cannot carry ads.",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPaidPlacementEntry"
            }
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "AiVisibilityPaidPlacementEntry": {
        "type": "object",
        "description": "One sponsored result shown inside an AI answer.",
        "properties": {
          "position": {
            "type": "integer",
            "description": "Order the ad was rendered in within the answer"
          },
          "blockPosition": {
            "type": "string",
            "nullable": true,
            "description": "Alignment of the sponsored block; null when the provider did not report one",
            "enum": [
              "LEFT",
              "RIGHT"
            ]
          },
          "blockText": {
            "type": "string",
            "nullable": true,
            "description": "The answer's own lead-in to the sponsored block"
          },
          "isRendered": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the ad was actually painted on screen. `false` means the engine was served the ad but never displayed it, so nobody saw it; `null` means the platform does not report visibility (every Google placement). Only `false` is excluded from the aggregated paid-placement counts."
          },
          "adUrl": {
            "type": "string",
            "nullable": true,
            "description": "Where the ad points: the campaign's landing page on ChatGPT, and the advertiser's homepage on Google, which does not expose the destination without following the ad click referral."
          },
          "advertiserUrl": {
            "type": "string",
            "nullable": true,
            "description": "The advertiser's own site, reported beside the ad. Not a duplicate of `adUrl`, which is usually a campaign landing page. Null on Google, which reports no such field."
          },
          "advertiserFaviconUrl": {
            "type": "string",
            "nullable": true,
            "description": "The icon shown next to the ad; null on Google, which reports none"
          },
          "normalizedDomain": {
            "type": "string",
            "nullable": true,
            "description": "Advertiser's registrable domain (eTLD+1); null when normalization failed"
          },
          "classification": {
            "type": "string",
            "nullable": true,
            "description": "The advertiser's relationship to this project's tracked brands; null when the domain is unknown",
            "enum": [
              "SELF",
              "COMPETITOR",
              "OTHER"
            ]
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "snippet": {
            "type": "string",
            "nullable": true
          },
          "websiteName": {
            "type": "string",
            "nullable": true
          },
          "breadcrumb": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AiVisibilityPaidAdvertiserEntry": {
        "type": "object",
        "description": "One advertiser's presence across the aggregated jobs.",
        "properties": {
          "domain": {
            "type": "string"
          },
          "classification": {
            "type": "string",
            "enum": [
              "SELF",
              "COMPETITOR",
              "OTHER"
            ]
          },
          "brandId": {
            "type": "string",
            "nullable": true,
            "description": "Set when the advertiser matches one of the project's tracked brands"
          },
          "brandName": {
            "type": "string",
            "nullable": true
          },
          "placementCount": {
            "type": "integer",
            "description": "Times this advertiser was shown across the aggregated answers"
          },
          "promptCount": {
            "type": "integer",
            "description": "Distinct prompts whose answers carried this advertiser's ad"
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Engines whose answers carried this advertiser's ad"
          },
          "sampleTitle": {
            "type": "string",
            "nullable": true,
            "description": "One of the advertiser's ad headlines, as competitor messaging intel"
          },
          "sampleSnippet": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AiVisibilityPaidPromptEntry": {
        "type": "object",
        "description": "One prompt whose answers carried advertising.",
        "properties": {
          "promptId": {
            "type": "string"
          },
          "promptText": {
            "type": "string",
            "nullable": true
          },
          "placementCount": {
            "type": "integer"
          },
          "runsWithAds": {
            "type": "integer",
            "description": "Answers for this prompt that carried at least one ad"
          },
          "advertiserDomains": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "competitorAdvertisers": {
            "type": "integer",
            "description": "How many of those advertisers are tracked competitors of this project"
          },
          "selfMentioned": {
            "type": "boolean",
            "description": "True when the project's own brand was named organically in at least one of this prompt's ad-carrying answers — i.e. someone is paying for a slot on an answer this brand already earned."
          }
        }
      },
      "AiVisibilityPaidPlacementsResponse": {
        "type": "object",
        "description": "Sponsored placements inside AI answers, aggregated over the same job window as every other AI visibility read. Only some platforms report ads, so the measured counts are scoped to those platforms — a zero here means \"no ads were shown\", never \"we did not look\". Ads a platform reported as served but never displayed are left out of every count: nobody saw them.",
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            },
            "description": "The ad-reporting engines this response was computed for"
          },
          "jobsIncluded": {
            "type": "integer"
          },
          "promptsMeasured": {
            "type": "integer",
            "description": "Distinct prompts actually asked on an ad-reporting engine in this window"
          },
          "promptsWithAds": {
            "type": "integer"
          },
          "runsMeasured": {
            "type": "integer"
          },
          "runsWithAds": {
            "type": "integer"
          },
          "advertisers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPaidAdvertiserEntry"
            }
          },
          "prompts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPaidPromptEntry"
            }
          }
        }
      },
      "AiVisibilityShareOfVoiceEntry": {
        "type": "object",
        "properties": {
          "brandId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "isSelf": {
            "type": "boolean"
          },
          "runsWithBrand": {
            "type": "integer"
          },
          "shareOfVoice": {
            "type": "number",
            "nullable": true,
            "description": "This brand's runsWithBrand divided by the sum across all brands for this job; null when no brand had presence"
          },
          "rank": {
            "type": "integer",
            "description": "1-based dense rank within the job, descending by runsWithBrand (ties broken by brandId)"
          },
          "previousRunsWithBrand": {
            "type": "integer",
            "description": "Runs this brand was present in across the whole comparison window. Present unless the read answers by job count; 0 when it was not present then.\n"
          },
          "previousShareOfVoice": {
            "type": "number",
            "nullable": true,
            "description": "This brand's share of voice across the comparison window taken as a whole — its runs-with-brand over every brand's, summed across that window's jobs. It is one figure per brand, repeated on every point, because the comparison window runs its own jobs on its own dates and no job here corresponds to a job there. Null when no brand had any presence in that window.\n"
          },
          "previousRank": {
            "type": "integer",
            "nullable": true,
            "description": "This brand's dense rank in that same window-wide aggregate, ranked exactly as `rank` is within a job. A brand the window measured but never featured is ranked, tied last with every other brand on nothing — it was there to be counted and came bottom. Null when the window holds no reading for the brand at all: a rank is a position, and inventing last place for a brand that was never measured would read as a climb it never made.\n"
          },
          "absoluteChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Change in shareOfVoice, in percentage points — a share of 0.4286 against 0.2857 reads as 14.3, the difference between the two figures as the page shows them. Null when either share is null (nobody had presence in that window).\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Relative change from previousShareOfVoice to shareOfVoice. Null when previousShareOfVoice is 0 or null.\n"
          }
        }
      },
      "AiVisibilityShareOfVoicePoint": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityShareOfVoiceEntry"
            }
          }
        }
      },
      "AiVisibilityShareOfVoiceResponse": {
        "type": "object",
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            },
            "description": "The engine selection this response was computed for (empty = every engine)"
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityShareOfVoicePoint"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityProviderEnum": {
        "type": "string",
        "enum": [
          "PERPLEXITY",
          "GEMINI",
          "CLAUDE",
          "CHATGPT",
          "DEEPSEEK",
          "GLM",
          "KIMI",
          "GOOGLE_AI_OVERVIEW",
          "GOOGLE_AI_MODE",
          "CHATGPT_WEB",
          "GEMINI_WEB"
        ],
        "description": "A single AI answer engine. Note this deliberately has NO 'ALL' member: \"all engines\" is expressed as an empty selection. Per-row `provider` fields elsewhere stay plain strings because the aggregation marks its cross-engine rollup row with the internal sentinel 'ALL'.\n"
      },
      "AiVisibilityExplorationSurfaceTypeEnum": {
        "type": "string",
        "enum": [
          "MODEL_API",
          "SEARCH_SURFACE"
        ],
        "description": "What kind of answer an engine produces. MODEL_API is a chat completion from a configured model (ChatGPT/Gemini/Claude/... APIs); SEARCH_SURFACE is a real consumer answer surface read through a SERP provider. They are not interchangeable evidence and clients must label them differently — a MODEL_API answer is not what a buyer sees on chatgpt.com.\n"
      },
      "AiVisibilityExplorationWebSearchModeEnum": {
        "type": "string",
        "enum": [
          "ENABLED",
          "DISABLED"
        ],
        "description": "Whether this engine grounds its answer in a live web search. Descriptive only: search behaviour is decided by the adapter and server config, not by the request, so there is no web-search toggle in v1.\n"
      },
      "AiVisibilityExplorationRunStatusEnum": {
        "type": "string",
        "enum": [
          "SUCCEEDED",
          "FAILED"
        ],
        "description": "Terminal state of one engine's answer. Explorations are synchronous, so a run is settled by the time it is returned; engines fail independently, and a FAILED engine never fails its siblings.\n"
      },
      "AiVisibilityExplorationRequest": {
        "type": "object",
        "required": [
          "promptText",
          "providers"
        ],
        "properties": {
          "promptText": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1024,
            "description": "The question to ask, verbatim. Same limit as a tracked prompt."
          },
          "providers": {
            "type": "array",
            "minItems": 1,
            "maxItems": 4,
            "description": "Engines to ask, from GET /ai-visibility/exploration-providers. Anything not in that response — unknown, unconfigured, plan-disallowed, or an async-only consumer surface — is rejected by name rather than silently dropped.\n",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            }
          },
          "region": {
            "description": "Vantage point to ask from; defaults to US. A region samples ONE of its configured countries per prompt (stable for the same prompt), so this is a regional reading, not an exact-country selector.\n",
            "allOf": [
              {
                "$ref": "#/components/schemas/AiVisibilityRegionEnum"
              }
            ]
          },
          "analyze": {
            "type": "boolean",
            "default": true,
            "description": "Run the brand extractor over each answer to detect tracked-brand mentions. Costs one extra LLM call per engine that has no reusable current-version analysis.\n"
          },
          "highlightBrand": {
            "type": "string",
            "maxLength": 250,
            "nullable": true,
            "description": "An arbitrary brand name to look for in every answer and citation, matched deterministically in code with no LLM involved. Independent of `analyze` and of the project's configured brands — this is how you check a name you do not track.\n"
          },
          "runFresh": {
            "type": "boolean",
            "default": false,
            "description": "Bypass the 7-day answer cache and pay every selected engine again. Off by default: an identical question asked from the same vantage point reuses the stored answer for free.\n"
          }
        }
      },
      "AiVisibilityExplorationCitationEntry": {
        "type": "object",
        "description": "One source an answer cited. Same fields as AiVisibilityCitationEntry plus `highlightMatched`, which is specific to this exploration's arbitrary highlight.\n",
        "properties": {
          "position": {
            "type": "integer"
          },
          "rawUrl": {
            "type": "string",
            "nullable": true
          },
          "normalizedDomain": {
            "type": "string",
            "nullable": true
          },
          "urlPath": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "snippet": {
            "type": "string",
            "nullable": true
          },
          "highlightMatched": {
            "type": "boolean",
            "description": "Whether this source matched the exploration's `highlightBrand` (always false when none was given)"
          }
        }
      },
      "AiVisibilityExplorationRun": {
        "type": "object",
        "description": "One engine's answer within an exploration. Flat `status` + nullable fields rather than a oneOf, matching AiVisibilityRunDetailResponse.\n",
        "properties": {
          "id": {
            "type": "string"
          },
          "provider": {
            "$ref": "#/components/schemas/AiVisibilityProviderEnum"
          },
          "market": {
            "type": "string",
            "description": "ISO-3166 alpha-2 country this engine was actually asked from"
          },
          "surfaceType": {
            "$ref": "#/components/schemas/AiVisibilityExplorationSurfaceTypeEnum"
          },
          "webSearchMode": {
            "$ref": "#/components/schemas/AiVisibilityExplorationWebSearchModeEnum"
          },
          "status": {
            "$ref": "#/components/schemas/AiVisibilityExplorationRunStatusEnum"
          },
          "modelVersion": {
            "type": "string",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "nullable": true,
            "description": "Customer-facing failure text; the upstream detail stays in the server log"
          },
          "answerText": {
            "type": "string",
            "nullable": true
          },
          "citations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityExplorationCitationEntry"
            }
          },
          "mentions": {
            "type": "array",
            "description": "Tracked-brand mentions only, in the existing SELF/COMPETITOR shape. Empty when analysis was not requested, was unavailable, or found no tracked brand.\n",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityMentionEntry"
            }
          },
          "highlightBrandMentioned": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the answer named `highlightBrand`; null when no highlight was requested"
          },
          "fanOutQueries": {
            "type": "array",
            "description": "The searches the engine ran to answer; empty when it reports none",
            "items": {
              "type": "string"
            }
          },
          "outputTokens": {
            "type": "integer",
            "nullable": true
          },
          "providerCacheHit": {
            "type": "boolean",
            "description": "True when this answer was copied from an earlier identical call instead of being paid for again"
          },
          "analysisCacheHit": {
            "type": "boolean",
            "description": "True when the brand analysis was re-derived from stored entities instead of re-extracted"
          },
          "cacheSourceRunId": {
            "type": "string",
            "nullable": true,
            "description": "The exploration run this answer was copied from; provenance only, and it may since have been pruned"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "AiVisibilityExplorationResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "promptText": {
            "type": "string"
          },
          "highlightBrand": {
            "type": "string",
            "nullable": true
          },
          "region": {
            "$ref": "#/components/schemas/AiVisibilityRegionEnum"
          },
          "analyzeRequested": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdByName": {
            "type": "string",
            "nullable": true
          },
          "results": {
            "type": "array",
            "description": "One entry per requested engine, in the order they were requested",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityExplorationRun"
            }
          }
        }
      },
      "AiVisibilityExplorationSummary": {
        "type": "object",
        "description": "One row of the exploration history list — enough to re-open it, no answers.",
        "properties": {
          "id": {
            "type": "string"
          },
          "promptText": {
            "type": "string"
          },
          "region": {
            "$ref": "#/components/schemas/AiVisibilityRegionEnum"
          },
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdByName": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AiVisibilityExplorationProviderEntry": {
        "type": "object",
        "properties": {
          "provider": {
            "$ref": "#/components/schemas/AiVisibilityProviderEnum"
          },
          "displayName": {
            "type": "string"
          },
          "surfaceType": {
            "$ref": "#/components/schemas/AiVisibilityExplorationSurfaceTypeEnum"
          },
          "webSearchMode": {
            "$ref": "#/components/schemas/AiVisibilityExplorationWebSearchModeEnum"
          }
        }
      },
      "AiVisibilityExplorationProvidersResponse": {
        "type": "object",
        "required": [
          "providers"
        ],
        "properties": {
          "providers": {
            "type": "array",
            "description": "The engines this organization can actually run an exploration against: configured SYNCHRONOUS adapters intersected with the plan's `ai_visibility_exploration_providers` value. Deliberately distinct from GET /ai-visibility/providers, which answers a tracking question and can include async consumer surfaces this path cannot execute. Empty means the plan grants none — render the form disabled, do not fall back to a hardcoded list.\n",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityExplorationProviderEntry"
            }
          }
        }
      },
      "AiVisibilityProviderSeriesEntry": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string"
          },
          "runCount": {
            "type": "integer"
          },
          "runsWithBrand": {
            "type": "integer"
          },
          "presenceRate": {
            "type": "number",
            "description": "runsWithBrand / runCount, 0..1"
          },
          "citationCount": {
            "type": "integer"
          },
          "mentionRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithMention / runCount, 0..1; null when not analyzed"
          },
          "citationRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithCitation / runCount, 0..1; null when not analyzed"
          }
        }
      },
      "AiVisibilityProviderSeriesPoint": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "entries": {
            "type": "array",
            "description": "One entry per AI provider (the 'ALL' rollup is excluded) for the project's own brand",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderSeriesEntry"
            }
          }
        }
      },
      "AiVisibilityProviderSeriesResponse": {
        "type": "object",
        "properties": {
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderSeriesPoint"
            }
          },
          "comparisonSeries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderSeriesPoint"
            },
            "description": "The same per-provider series read over the comparison window, under the same\nengine, topic and region filters. Present unless the read answers by job count.\n\nIts points are that window's own jobs, carrying their own ids and finish\ntimes, so a chart lines the two up by position rather than by date — the two\nwindows rarely run the same number of jobs. An engine that only ran in the\ncomparison window appears here and not in `points`, and one that only ran in\nthe selected period has the reverse.\n"
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityCompetitorSeriesEntry": {
        "type": "object",
        "properties": {
          "brandId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "isSelf": {
            "type": "boolean"
          },
          "runCount": {
            "type": "integer"
          },
          "runsWithBrand": {
            "type": "integer"
          },
          "presenceRate": {
            "type": "number",
            "description": "runsWithBrand / runCount, 0..1"
          },
          "citationCount": {
            "type": "integer"
          },
          "mentionRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithMention / runCount, 0..1; null when not analyzed"
          },
          "citationRate": {
            "type": "number",
            "nullable": true,
            "description": "runsWithCitation / runCount, 0..1; null when not analyzed"
          },
          "shareOfVoice": {
            "type": "number",
            "nullable": true,
            "description": "This brand's runsWithBrand divided by the sum across all brands for this job; null when no brand had presence"
          }
        }
      },
      "AiVisibilityCompetitorSeriesPoint": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "entries": {
            "type": "array",
            "description": "One entry per tracked brand (the project's own brand plus every competitor) for the requested provider",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityCompetitorSeriesEntry"
            }
          }
        }
      },
      "AiVisibilityCompetitorSeriesResponse": {
        "type": "object",
        "properties": {
          "providers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityProviderEnum"
            },
            "description": "The engine selection this response was computed for (empty = every engine)"
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityCompetitorSeriesPoint"
            }
          }
        }
      },
      "AiVisibilityPromptProviderCell": {
        "type": "object",
        "description": "One prompt's metrics on one engine, or — when `provider` is absent — that prompt's rollup across every engine it ran on. The previous* and change fields are filled only when a comparison was requested, and describe the same cell over the comparison window.\n",
        "properties": {
          "provider": {
            "type": "string"
          },
          "runCount": {
            "type": "integer"
          },
          "runsWithBrand": {
            "type": "integer"
          },
          "presenceRate": {
            "type": "number"
          },
          "visibilityRank": {
            "type": "integer",
            "nullable": true,
            "description": "Self brand's rank among all tracked brands by answer visibility for this prompt (1 = most visible, standard competition ranking); null when no tracked brand is visible in the prompt's answers.\n"
          },
          "runsWithMention": {
            "type": "integer",
            "nullable": true
          },
          "runsWithCitation": {
            "type": "integer",
            "nullable": true
          },
          "recommendedCount": {
            "type": "integer",
            "nullable": true
          },
          "answerRankSum": {
            "type": "integer",
            "nullable": true
          },
          "answerRankCount": {
            "type": "integer",
            "nullable": true
          },
          "previousRunCount": {
            "type": "integer",
            "description": "Answers this cell covered in the comparison window, under the same engine, topic and region filters. Present unless the read answers by job count; 0 when the prompt was not run then.\n"
          },
          "previousRunsWithBrand": {
            "type": "integer",
            "description": "How many of those answers the brand was present in. Present unless the read answers by job count.\n"
          },
          "previousPresenceRate": {
            "type": "number",
            "nullable": true,
            "description": "previousRunsWithBrand / previousRunCount, 0..1. Null — never 0 — when the prompt was not run in the comparison window at all: no answers is not the same reading as answers the brand was absent from, and 0 would show a prompt that has since started running as a collapse to nothing.\n"
          },
          "previousAvgAnswerRank": {
            "type": "number",
            "nullable": true,
            "description": "Where the brand placed in the comparison window's answers, on average. Reported already divided, unlike the selected period's `answerRankSum` and `answerRankCount`, because there is nothing here to re-aggregate it with — it is the figure `answerRankSum / answerRankCount` is compared against. Null — never 0 — when no answer there ranked the brand: 0 is the best position there is, not the absence of one.\n"
          },
          "absoluteChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Change in presenceRate, in percentage points (presence is what the row is read for, so the change fields describe it). A rate of 0.4286 against 0.2857 reads as 14.3 — the difference between the two figures as the page shows them. Null when previousPresenceRate is null.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Relative change from previousPresenceRate to presenceRate. Null when previousPresenceRate is 0 or null — there is no percentage that describes going from nothing to something.\n"
          }
        }
      },
      "AiVisibilityPromptBreakdownEntry": {
        "type": "object",
        "properties": {
          "promptId": {
            "type": "string"
          },
          "text": {
            "type": "string",
            "nullable": true
          },
          "intentTier": {
            "type": "string",
            "nullable": true
          },
          "active": {
            "type": "boolean"
          },
          "currentTopicId": {
            "type": "string",
            "nullable": true,
            "description": "The prompt's current configured topic, independent of the historical run snapshot filter."
          },
          "currentTopicName": {
            "type": "string",
            "nullable": true,
            "description": "The prompt's current configured topic name."
          },
          "overall": {
            "$ref": "#/components/schemas/AiVisibilityPromptProviderCell"
          },
          "byProvider": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPromptProviderCell"
            }
          }
        }
      },
      "AiVisibilityPromptsBreakdownResponse": {
        "type": "object",
        "description": "The prompts the selected period ran. Which prompts appear is decided by that\nperiod alone — a prompt that ran only in the comparison window is not listed,\nand neither is an engine cell it only has there.\n",
        "properties": {
          "jobsIncluded": {
            "type": "integer"
          },
          "comparisonJobsIncluded": {
            "type": "integer",
            "description": "Completed jobs the comparison figures were read from, counted the same way as jobsIncluded. Present unless the read answers by job count. 0 says the project ran no analysis in that window at all — which is why every prompt's previous figures are absent — as opposed to having run and found nothing.\n"
          },
          "prompts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPromptBreakdownEntry"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityTopicRequest": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          }
        }
      },
      "AiVisibilityTopicResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "promptCount": {
            "type": "integer"
          },
          "archived": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AiVisibilityBreakdownBrandMetrics": {
        "type": "object",
        "description": "One brand's standing inside one breakdown row. The previous* and change fields are filled only by reads that accept a comparison — the persona breakdown does not, so they are always absent there.\n",
        "properties": {
          "brandId": {
            "type": "string"
          },
          "brandName": {
            "type": "string"
          },
          "isSelf": {
            "type": "boolean"
          },
          "runsWithBrand": {
            "type": "integer"
          },
          "visibilityRate": {
            "type": "number",
            "nullable": true
          },
          "shareOfVoice": {
            "type": "number",
            "nullable": true
          },
          "previousRunsWithBrand": {
            "type": "integer",
            "description": "Runs this brand was present in within this row during the comparison window; 0 when it was not present then."
          },
          "previousVisibilityRate": {
            "type": "number",
            "nullable": true,
            "description": "This brand's visibility rate within this row over the comparison window; null when the row had no runs then."
          },
          "previousShareOfVoice": {
            "type": "number",
            "nullable": true,
            "description": "This brand's share of voice within this row over the comparison window; null when no brand had presence there then."
          },
          "absoluteChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Change in visibilityRate, in percentage points — a rate of 0.4286 against 0.2857 reads as 14.3. Null when either rate is null (the row had no runs in one of the windows).\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Relative change from previousVisibilityRate to visibilityRate. Null when previousVisibilityRate is 0 or null.\n"
          }
        }
      },
      "AiVisibilityTopicBreakdownEntry": {
        "type": "object",
        "properties": {
          "topicId": {
            "type": "string",
            "nullable": true
          },
          "topicName": {
            "type": "string",
            "nullable": true
          },
          "archived": {
            "type": "boolean"
          },
          "promptsWithRuns": {
            "type": "integer"
          },
          "runCount": {
            "type": "integer"
          },
          "brands": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityBreakdownBrandMetrics"
            }
          },
          "previousRunCount": {
            "type": "integer",
            "description": "Runs measured for this topic in the comparison window. Present unless the read answers by job count; 0 when the topic was not covered then.\n"
          },
          "previousPromptsWithRuns": {
            "type": "integer",
            "description": "Prompts of this topic that produced runs in the comparison window. Present unless the read answers by job count."
          },
          "absoluteChange": {
            "type": "integer",
            "description": "runCount - previousRunCount. How much the topic was measured is the row's own metric, so the change fields describe it; each brand's visibility change is on its own entry under `brands`. Present unless the read answers by job count.\n"
          },
          "percentageChange": {
            "type": "number",
            "format": "double",
            "nullable": true,
            "description": "Percentage change from previousRunCount to runCount. Null when previousRunCount is 0.\n"
          }
        }
      },
      "AiVisibilityTopicsBreakdownResponse": {
        "type": "object",
        "description": "The topics the selected period covers. A topic that saw runs only in the\ncomparison window is not listed on that account alone — an active topic is always\nlisted, and an archived one appears only when the selected period has runs for it.\n",
        "properties": {
          "topics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityTopicBreakdownEntry"
            }
          },
          "comparisonWindow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ComparisonWindow"
              }
            ]
          }
        }
      },
      "AiVisibilityTopicBackfillRequest": {
        "type": "object",
        "properties": {
          "promptIds": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "type": "string"
            }
          },
          "dryRun": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "AiVisibilityTopicBackfillResponse": {
        "type": "object",
        "properties": {
          "eligibleRuns": {
            "type": "integer"
          },
          "runsRetagged": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "AiVisibilityPersonaRequest": {
        "type": "object",
        "required": [
          "name",
          "description"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000,
            "description": "3-5 sentences covering this buyer's goals, pain points, and the vocabulary they would actually type. Used to seed prompt generation and to label results — never sent to an answer engine.\n"
          }
        }
      },
      "AiVisibilityPersonaResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "promptCount": {
            "type": "integer"
          },
          "archived": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AiVisibilityPersonaBreakdownEntry": {
        "type": "object",
        "properties": {
          "personaId": {
            "type": "string",
            "nullable": true,
            "description": "Null is the \"no persona\" bucket."
          },
          "personaName": {
            "type": "string",
            "nullable": true
          },
          "archived": {
            "type": "boolean"
          },
          "promptsWithRuns": {
            "type": "integer"
          },
          "runCount": {
            "type": "integer"
          },
          "brands": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityBreakdownBrandMetrics"
            }
          }
        }
      },
      "AiVisibilityPersonasBreakdownResponse": {
        "type": "object",
        "properties": {
          "personas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPersonaBreakdownEntry"
            }
          }
        }
      },
      "AiVisibilityPersonaBackfillRequest": {
        "type": "object",
        "properties": {
          "promptIds": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "type": "string"
            }
          },
          "dryRun": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "AiVisibilityPersonaBackfillResponse": {
        "type": "object",
        "properties": {
          "eligibleRuns": {
            "type": "integer"
          },
          "runsRetagged": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "AiVisibilityPersonaSuggestionsRequest": {
        "type": "object",
        "required": [
          "brandName"
        ],
        "properties": {
          "brandName": {
            "type": "string",
            "maxLength": 255
          },
          "primaryDomain": {
            "type": "string",
            "maxLength": 255
          }
        }
      },
      "AiVisibilityPersonaDraft": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "AiVisibilityPersonaSuggestionsResponse": {
        "type": "object",
        "properties": {
          "personas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AiVisibilityPersonaDraft"
            },
            "description": "Drafts for review — nothing is persisted. An auto-generated persona is reliably too broad to be useful, so it becomes real only when someone edits and saves it.\n"
          }
        }
      },
      "BacklinkSourceStatusEnum": {
        "type": "string",
        "enum": [
          "active",
          "ignored"
        ],
        "description": "Whether the backlink source is shown (active) or dismissed as noise (ignored)"
      },
      "BacklinkSourceResponse": {
        "type": "object",
        "required": [
          "domain",
          "status",
          "sessions",
          "stale"
        ],
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Backlink source ID, for the status-update endpoint. Null means this domain is known from the link graph only — it has never referred a session, so there is no source row to ignore or restore and the curation action must be hidden. Only appears under status=lost.\n"
          },
          "domain": {
            "type": "string",
            "description": "Normalized referring host (lowercased, www-stripped)"
          },
          "status": {
            "$ref": "#/components/schemas/BacklinkSourceStatusEnum"
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "First session ever referred by this domain (historical, not sweep time). Null for a link-graph-only domain that never sent traffic.\n"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "sampleReferrerUrl": {
            "type": "string",
            "nullable": true,
            "description": "A verbatim referrer URL from this domain — the exact linking page when the browser sent a full referrer"
          },
          "firstLandingPath": {
            "type": "string",
            "nullable": true,
            "description": "Landing path of the earliest referred session"
          },
          "sessions": {
            "type": "integer",
            "description": "Sessions referred by this domain within the selected window"
          },
          "topLandingPath": {
            "type": "string",
            "nullable": true,
            "description": "Most common landing path within the selected window"
          },
          "lostAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Provider-reported date the link from this domain disappeared. Null means either still linking or not present in the link graph at all — liveness is a separate axis from the active/ignored status.\n"
          },
          "domainRank": {
            "type": "integer",
            "nullable": true,
            "description": "Link-graph authority rank (0–1000) of the referring domain; null when the domain is not in the graph"
          },
          "spamScore": {
            "type": "integer",
            "nullable": true,
            "description": "DataForSEO spam score (0–100, higher is spammier) of the referring domain's links; null when the domain is not in the graph or the provider returned none\n"
          },
          "backlinksCount": {
            "type": "integer",
            "nullable": true,
            "description": "Total links from this domain to the site, per the link graph; null when the domain is not in the graph"
          },
          "observedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "The most recent refresh in which the provider still returned this domain. Null for a traffic-only domain that is not in the link graph.\n"
          },
          "stale": {
            "type": "boolean",
            "description": "True when the latest refresh did not return this domain, so its rank and counts are left over from an earlier one. A domain drops out mainly by falling below the stored top-N rank cap, which is NOT the same as the link being lost — hence a separate flag from lostAt. Always false for traffic-only domains, which the provider never reported in the first place.\n"
          }
        }
      },
      "BacklinkSourcesResponse": {
        "type": "object",
        "required": [
          "items",
          "page",
          "size",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BacklinkSourceResponse"
            }
          },
          "page": {
            "type": "integer",
            "description": "Zero-based index of the returned page of results"
          },
          "size": {
            "type": "integer",
            "description": "Maximum number of sources returned per result page"
          },
          "total": {
            "type": "integer",
            "description": "Number of sources matching the current filter/search"
          }
        }
      },
      "BacklinkTimelinePoint": {
        "type": "object",
        "required": [
          "date",
          "sessions"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "sessions": {
            "type": "integer",
            "description": "Sessions referred by the domain that day"
          }
        }
      },
      "BacklinkLandingPath": {
        "type": "object",
        "required": [
          "path",
          "sessions"
        ],
        "properties": {
          "path": {
            "type": "string"
          },
          "sessions": {
            "type": "integer"
          }
        }
      },
      "BacklinkSourceDetailResponse": {
        "type": "object",
        "required": [
          "domain",
          "status",
          "firstSeenAt",
          "lastSeenAt",
          "timeline",
          "landingPaths",
          "sourceUrls"
        ],
        "properties": {
          "domain": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/BacklinkSourceStatusEnum"
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time"
          },
          "timeline": {
            "type": "array",
            "description": "Daily referred sessions within the selected window",
            "items": {
              "$ref": "#/components/schemas/BacklinkTimelinePoint"
            }
          },
          "landingPaths": {
            "type": "array",
            "description": "Landing paths of referred sessions within the selected window",
            "items": {
              "$ref": "#/components/schemas/BacklinkLandingPath"
            }
          },
          "sourceUrls": {
            "type": "array",
            "description": "Distinct verbatim referrer URLs seen from this domain — the pages that link to the site",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "UpdateBacklinkSourceRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "$ref": "#/components/schemas/BacklinkSourceStatusEnum"
          }
        }
      },
      "BacklinkReclamationItem": {
        "type": "object",
        "required": [
          "path",
          "httpStatus",
          "sessions",
          "referrerDomains"
        ],
        "properties": {
          "path": {
            "type": "string",
            "description": "Normalized path that referred visitors land on"
          },
          "httpStatus": {
            "type": "integer",
            "description": "HTTP status the site crawler recorded for this page (non-2xx)"
          },
          "sessions": {
            "type": "integer",
            "description": "Externally referred sessions that landed on this dead page within the window"
          },
          "referrerDomains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Referring domains still sending traffic to this page"
          },
          "lastHitAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Most recent referred session that hit this page"
          }
        }
      },
      "BacklinkReclamationResponse": {
        "type": "object",
        "required": [
          "items",
          "siteIndexAvailable"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BacklinkReclamationItem"
            }
          },
          "siteIndexAvailable": {
            "type": "boolean",
            "description": "False when the project has never finished a site audit — reclamation matches inbound links against crawled pages, and there are none to match"
          }
        }
      },
      "BacklinkOpportunityEntry": {
        "type": "object",
        "required": [
          "domain",
          "citationCount",
          "promptCount",
          "gapPromptCount",
          "providers",
          "alreadyLinking"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "description": "Third-party domain cited by AI answers for this project's prompts"
          },
          "sourceType": {
            "type": "string",
            "nullable": true,
            "description": "Static source-type sub-classification; null when the job predates it",
            "enum": [
              "VENDOR",
              "UGC",
              "REVIEW_SITE",
              "REFERENCE",
              "NEWS",
              "SOCIAL",
              "DOCS",
              "MARKETPLACE",
              "EDITORIAL"
            ]
          },
          "citationCount": {
            "type": "integer",
            "description": "Citations of this domain across the aggregated jobs"
          },
          "promptCount": {
            "type": "integer",
            "description": "Distinct prompts whose answers cited this domain"
          },
          "gapPromptCount": {
            "type": "integer",
            "description": "Prompts with zero self-brand presence whose answers cited this domain — the outreach priority signal"
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "AI engines that cited this domain at least once in the aggregated jobs"
          },
          "alreadyLinking": {
            "type": "boolean",
            "description": "True when this domain already appears as a detected backlink source for the project"
          },
          "sampleUrls": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to a few cited URLs on this domain, as returned by the engines"
          },
          "marketplaceSiteId": {
            "type": "string",
            "nullable": true,
            "description": "Set when this domain is purchasable in the guest-post marketplace — deep-links the opportunity to the catalog. Null when the marketplace is disabled or does not carry the domain."
          },
          "purchasableFromCents": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Cheapest retail placement price on this domain in USD cents; null when not purchasable"
          }
        }
      },
      "BacklinkOpportunitiesResponse": {
        "type": "object",
        "required": [
          "items",
          "jobsIncluded",
          "totalDomains"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BacklinkOpportunityEntry"
            }
          },
          "jobsIncluded": {
            "type": "integer",
            "description": "Number of completed AI-visibility jobs aggregated"
          },
          "totalDomains": {
            "type": "integer",
            "description": "Candidate domains found before `limit` truncated the list. Equal to `items.length` when nothing was dropped, so a client can say how many rows it is not showing.\n"
          }
        }
      },
      "BacklinkCompetitorGapEntry": {
        "type": "object",
        "required": [
          "domain",
          "competitorDomains",
          "competitorCount"
        ],
        "properties": {
          "domain": {
            "type": "string",
            "description": "Normalized referring host that links to competitors but not to this site"
          },
          "competitorDomains": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tracked competitor domains this source links to"
          },
          "competitorCount": {
            "type": "integer",
            "description": "Number of tracked competitors linked to — the primary ranking signal"
          },
          "domainRank": {
            "type": "integer",
            "nullable": true,
            "description": "Authority rank (0–1000) of the referring domain"
          },
          "spamScore": {
            "type": "integer",
            "nullable": true,
            "description": "DataForSEO spam score (0–100, higher is spammier) of the referring domain's links"
          },
          "backlinksCount": {
            "type": "integer",
            "nullable": true,
            "description": "Links this domain points at the competitor set"
          }
        }
      },
      "BacklinkCompetitorGapResponse": {
        "type": "object",
        "required": [
          "items",
          "trackedCompetitors",
          "competitors"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BacklinkCompetitorGapEntry"
            }
          },
          "trackedCompetitors": {
            "type": "integer",
            "description": "How many competitor brands with a resolvable domain the project tracks. Zero means the gap list cannot be computed at all (nothing to compare against) rather than \"computed and found nothing\" — the two need different empty states. Resolved server-side so clients never have to re-derive the competitor predicate."
          },
          "competitors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The competitor domains the stored gap actually names, sorted — the valid values for the competitor filter. Derived from the gap rows rather than from the tracked-brand list, because a refresh compares against a capped number of brands and a brand added since the last refresh appears in no row: offering it would be a filter that can only ever return nothing."
          },
          "competitorsWithoutProfile": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tracked competitors whose link profile has never been pulled, sorted. They contribute nothing to the gap, so an empty list with tracked competitors present means \"pull their profiles\" rather than \"there is no gap\" — the client cannot tell those apart on its own."
          },
          "appliedCompetitor": {
            "type": "string",
            "nullable": true,
            "description": "The normalized competitor filter this response was built with; null when unfiltered. Lets a client confirm what it is looking at without re-deriving the normalization."
          },
          "computedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the gap list was last recomputed; null when it has never run. Read unfiltered, so a competitor filter that matches nothing still reports the real value — an empty items array with a non-null computedAt means \"no matches\", not \"never computed\"."
          }
        }
      },
      "BacklinkLinkEntry": {
        "type": "object",
        "required": [
          "sourceDomain",
          "urlFrom",
          "urlTo"
        ],
        "properties": {
          "sourceDomain": {
            "type": "string",
            "description": "Normalized referring host (lowercased, www-stripped) the linking page belongs to"
          },
          "urlFrom": {
            "type": "string",
            "description": "The exact page that links to the site, verbatim from the provider"
          },
          "urlTo": {
            "type": "string",
            "description": "The page on the site the link points to"
          },
          "anchor": {
            "type": "string",
            "nullable": true,
            "description": "Anchor text of the link; null when the link has none (e.g. an image link)"
          },
          "dofollow": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the link passes authority; null when the provider did not say"
          },
          "linkRank": {
            "type": "integer",
            "nullable": true,
            "description": "DataForSEO rank (0–1000) of this individual backlink"
          },
          "spamScore": {
            "type": "integer",
            "nullable": true,
            "description": "DataForSEO spam score (0–100, higher is spammier) of this individual backlink"
          },
          "firstSeenAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the provider first crawled this link"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the provider last confirmed this link"
          }
        }
      },
      "BacklinkLinksResponse": {
        "type": "object",
        "required": [
          "items",
          "page",
          "size",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BacklinkLinkEntry"
            }
          },
          "page": {
            "type": "integer",
            "description": "Zero-based index of the returned page of results"
          },
          "size": {
            "type": "integer",
            "description": "Maximum number of links returned per result page"
          },
          "total": {
            "type": "integer",
            "description": "Number of stored links matching the current filter/search"
          },
          "observedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the stored link list was last refreshed; null when no refresh has stored links yet"
          }
        }
      },
      "DeleteBacklinkSyncedDataResponse": {
        "type": "object",
        "required": [
          "deletedDomains",
          "deletedLinks",
          "deletedGaps"
        ],
        "properties": {
          "deletedDomains": {
            "type": "integer",
            "description": "Referring-domain snapshot rows removed"
          },
          "deletedLinks": {
            "type": "integer",
            "description": "Exact-link rows removed"
          },
          "deletedGaps": {
            "type": "integer",
            "description": "Competitor-gap rows removed"
          }
        }
      },
      "KeywordDataProviderEnum": {
        "type": "string",
        "description": "Which DataForSEO API serves keyword data for a market. Not a preference — a coverage fact that decides what a row costs and which of its columns are necessarily null. `google_ads` markets carry no keyword difficulty and no search intent.\n",
        "enum": [
          "labs",
          "google_ads"
        ]
      },
      "KeywordLanguageResponse": {
        "type": "object",
        "required": [
          "code",
          "label"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "DataForSEO language code (e.g. `en`, `zh-TW`)"
          },
          "label": {
            "type": "string"
          }
        }
      },
      "KeywordMarketResponse": {
        "type": "object",
        "required": [
          "locationCode",
          "label",
          "shortLabel",
          "defaultLanguageCode",
          "provider",
          "languages"
        ],
        "properties": {
          "locationCode": {
            "type": "integer",
            "description": "DataForSEO location code (e.g. 2840 = United States)"
          },
          "label": {
            "type": "string",
            "description": "Country name"
          },
          "shortLabel": {
            "type": "string",
            "description": "Two-letter display code; `UK` rather than ISO's `GB`"
          },
          "defaultLanguageCode": {
            "type": "string",
            "description": "Used when a request names a market but no language"
          },
          "provider": {
            "$ref": "#/components/schemas/KeywordDataProviderEnum"
          },
          "languages": {
            "type": "array",
            "description": "Every language DataForSEO serves in this country. A combination outside this list is rejected before any provider call — the keyword-data APIs charge for a task they then reject as \"Invalid Field: 'language_code'.\"\n",
            "items": {
              "$ref": "#/components/schemas/KeywordLanguageResponse"
            }
          }
        }
      },
      "KeywordMarketsResponse": {
        "type": "object",
        "required": [
          "markets",
          "defaultLocationCode"
        ],
        "properties": {
          "markets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordMarketResponse"
            }
          },
          "defaultLocationCode": {
            "type": "integer",
            "description": "The market used when neither the request nor the project names one"
          }
        }
      },
      "KeywordIntentEnum": {
        "type": "string",
        "description": "What a searcher is trying to do, from DataForSEO's search intent analysis. `unknown` covers both \"the provider was unsure\" and \"this market has no intent data at all\" — Google-Ads-served countries never carry it.\n",
        "enum": [
          "informational",
          "commercial",
          "transactional",
          "navigational",
          "unknown"
        ]
      },
      "KeywordResearchModeEnum": {
        "type": "string",
        "description": "Which idea source to ask. `auto` walks related → suggestions → ideas and stops as soon as it has enough non-seed keywords, so it costs between one and three billed calls. Google-Ads-served markets have no source modes and normalize to `auto`.\n",
        "enum": [
          "auto",
          "related",
          "suggestions",
          "ideas"
        ]
      },
      "KeywordResearchSourceEnum": {
        "type": "string",
        "description": "The source that actually produced the returned rows.",
        "enum": [
          "related",
          "suggestions",
          "ideas",
          "google_ads"
        ]
      },
      "MonthlySearchResponse": {
        "type": "object",
        "required": [
          "year",
          "month",
          "searchVolume"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "month": {
            "type": "integer"
          },
          "searchVolume": {
            "type": "integer"
          }
        }
      },
      "KeywordRowResponse": {
        "type": "object",
        "description": "One keyword and its market metrics. Every metric is nullable, and null means \"the provider does not measure this here\" — never zero. Google-Ads-served markets return no `keywordDifficulty` and always `unknown` intent.\n",
        "required": [
          "keyword",
          "intent",
          "monthlySearches"
        ],
        "properties": {
          "keyword": {
            "type": "string"
          },
          "searchVolume": {
            "type": "integer",
            "nullable": true,
            "description": "Average monthly searches"
          },
          "cpc": {
            "type": "number",
            "nullable": true,
            "description": "Average cost per click in USD"
          },
          "competition": {
            "type": "number",
            "nullable": true,
            "description": "Paid competition, 0-1"
          },
          "keywordDifficulty": {
            "type": "integer",
            "nullable": true,
            "description": "Organic ranking difficulty, 0-100. Null in Google-Ads-served markets."
          },
          "intent": {
            "$ref": "#/components/schemas/KeywordIntentEnum"
          },
          "monthlySearches": {
            "type": "array",
            "description": "Up to twelve months of volume history, newest first",
            "items": {
              "$ref": "#/components/schemas/MonthlySearchResponse"
            }
          }
        }
      },
      "ResearchKeywordsRequest": {
        "type": "object",
        "required": [
          "seedKeyword"
        ],
        "properties": {
          "seedKeyword": {
            "type": "string",
            "maxLength": 255,
            "description": "The topic to expand. Trimmed and lowercased server-side."
          },
          "locationCode": {
            "type": "integer",
            "nullable": true,
            "description": "Overrides the project's default market. Omit to use the project's stored market (US when it has none)."
          },
          "languageCode": {
            "type": "string",
            "nullable": true,
            "description": "Overrides the market's default language. Rejected with 400 when DataForSEO does not serve it in that country."
          },
          "resultLimit": {
            "type": "integer",
            "default": 150,
            "enum": [
              150,
              300,
              500
            ],
            "description": "Rows to request. Labs bills per row, so this is a price knob."
          },
          "mode": {
            "$ref": "#/components/schemas/KeywordResearchModeEnum"
          },
          "clickstream": {
            "type": "boolean",
            "default": false,
            "description": "Buy clickstream-refined search volumes. DOUBLES the request price and is ignored in Google-Ads-served markets, which do not offer it."
          }
        }
      },
      "KeywordSourceAttemptResponse": {
        "type": "object",
        "description": "One billed provider call inside an `auto` walk.",
        "required": [
          "source",
          "rows",
          "nonSeedRows",
          "satisfiedThreshold"
        ],
        "properties": {
          "source": {
            "$ref": "#/components/schemas/KeywordResearchSourceEnum"
          },
          "rows": {
            "type": "integer"
          },
          "nonSeedRows": {
            "type": "integer",
            "description": "Rows other than the seed itself — what the threshold measures"
          },
          "satisfiedThreshold": {
            "type": "boolean"
          }
        }
      },
      "KeywordResearchDiagnosticsResponse": {
        "type": "object",
        "description": "Why the answer looks the way it does. Persisted with the cached result, so a cached `auto` answer can still say which of its up-to-three calls produced the rows.\n",
        "required": [
          "requestedMode",
          "minNonSeedThreshold",
          "attempts"
        ],
        "properties": {
          "requestedMode": {
            "$ref": "#/components/schemas/KeywordResearchModeEnum"
          },
          "minNonSeedThreshold": {
            "type": "integer"
          },
          "attempts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordSourceAttemptResponse"
            }
          }
        }
      },
      "KeywordResearchResponse": {
        "type": "object",
        "required": [
          "rows",
          "source",
          "usedFallback",
          "diagnostics",
          "fromCache",
          "fetchedAt",
          "locationCode",
          "languageCode",
          "provider"
        ],
        "properties": {
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordRowResponse"
            }
          },
          "source": {
            "$ref": "#/components/schemas/KeywordResearchSourceEnum"
          },
          "usedFallback": {
            "type": "boolean",
            "description": "True when the requested source was thin and another one served the rows"
          },
          "diagnostics": {
            "$ref": "#/components/schemas/KeywordResearchDiagnosticsResponse"
          },
          "fromCache": {
            "type": "boolean",
            "description": "True when this answer cost nothing — show the caller how old it is"
          },
          "fetchedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the underlying provider call was made, cached or not"
          },
          "locationCode": {
            "type": "integer",
            "description": "The market actually used, after project defaults were applied"
          },
          "languageCode": {
            "type": "string"
          },
          "provider": {
            "$ref": "#/components/schemas/KeywordDataProviderEnum"
          }
        }
      },
      "KeywordSerpRequest": {
        "type": "object",
        "required": [
          "keyword"
        ],
        "properties": {
          "keyword": {
            "type": "string",
            "maxLength": 255
          },
          "locationCode": {
            "type": "integer",
            "nullable": true
          },
          "languageCode": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SerpResultRowResponse": {
        "type": "object",
        "required": [
          "rank",
          "title",
          "url",
          "domain"
        ],
        "properties": {
          "rank": {
            "type": "integer",
            "description": "Position among ORGANIC results, so ads do not inflate it"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "etv": {
            "type": "number",
            "nullable": true,
            "description": "Provider's estimated monthly organic traffic value for this position"
          },
          "estimatedPaidTrafficCost": {
            "type": "number",
            "nullable": true,
            "description": "What the same traffic would cost to buy"
          },
          "referringDomains": {
            "type": "integer",
            "nullable": true
          },
          "backlinks": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "KeywordSerpNoResultsReasonEnum": {
        "type": "string",
        "description": "Why the result set is empty, when it is.",
        "enum": [
          "no_organic_results"
        ]
      },
      "KeywordSerpResponse": {
        "type": "object",
        "required": [
          "keyword",
          "items",
          "fromCache",
          "fetchedAt",
          "locationCode",
          "languageCode"
        ],
        "properties": {
          "keyword": {
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SerpResultRowResponse"
            }
          },
          "reason": {
            "$ref": "#/components/schemas/KeywordSerpNoResultsReasonEnum"
          },
          "fromCache": {
            "type": "boolean"
          },
          "fetchedAt": {
            "type": "string",
            "format": "date-time"
          },
          "locationCode": {
            "type": "integer"
          },
          "languageCode": {
            "type": "string"
          }
        }
      },
      "SavedKeywordSortEnum": {
        "type": "string",
        "default": "createdAt",
        "enum": [
          "createdAt",
          "keyword",
          "searchVolume",
          "cpc",
          "competition",
          "keywordDifficulty",
          "fetchedAt"
        ]
      },
      "SavedKeywordTagRefResponse": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string",
            "nullable": true,
            "description": "Palette key, not a hex value — the dashboard owns what each key renders as"
          }
        }
      },
      "SavedKeywordResponse": {
        "type": "object",
        "required": [
          "id",
          "keyword",
          "locationCode",
          "languageCode",
          "createdAt",
          "intent",
          "monthlySearches",
          "tags"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "keyword": {
            "type": "string"
          },
          "locationCode": {
            "type": "integer"
          },
          "languageCode": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "searchVolume": {
            "type": "integer",
            "nullable": true
          },
          "cpc": {
            "type": "number",
            "nullable": true
          },
          "competition": {
            "type": "number",
            "nullable": true
          },
          "keywordDifficulty": {
            "type": "integer",
            "nullable": true
          },
          "intent": {
            "$ref": "#/components/schemas/KeywordIntentEnum"
          },
          "monthlySearches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonthlySearchResponse"
            }
          },
          "fetchedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When these metrics were last fetched; null when they never have been"
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SavedKeywordTagRefResponse"
            }
          }
        }
      },
      "PaginatedSavedKeywordResponse": {
        "type": "object",
        "required": [
          "items",
          "page",
          "size",
          "total"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SavedKeywordResponse"
            }
          },
          "page": {
            "type": "integer"
          },
          "size": {
            "type": "integer"
          },
          "total": {
            "type": "integer",
            "description": "Rows matching the current filters, not rows in the project"
          }
        }
      },
      "SavedKeywordMetricInput": {
        "type": "object",
        "description": "Metrics the caller already holds for a keyword, carried inline so the save costs nothing. Omit any the caller does not have — a missing metric stays null rather than becoming zero.\n",
        "required": [
          "keyword"
        ],
        "properties": {
          "keyword": {
            "type": "string"
          },
          "searchVolume": {
            "type": "integer",
            "nullable": true
          },
          "cpc": {
            "type": "number",
            "nullable": true
          },
          "competition": {
            "type": "number",
            "nullable": true
          },
          "keywordDifficulty": {
            "type": "integer",
            "nullable": true
          },
          "intent": {
            "$ref": "#/components/schemas/KeywordIntentEnum"
          },
          "monthlySearches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonthlySearchResponse"
            }
          }
        }
      },
      "KeywordTagModeEnum": {
        "type": "string",
        "description": "`append` adds the given tags; `replace` removes every existing tag from the affected keywords first.\n",
        "enum": [
          "append",
          "replace"
        ]
      },
      "SaveKeywordsRequest": {
        "type": "object",
        "required": [
          "keywords"
        ],
        "properties": {
          "keywords": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "type": "string"
            }
          },
          "locationCode": {
            "type": "integer",
            "nullable": true,
            "description": "Market to save them for; defaults to the project's own"
          },
          "languageCode": {
            "type": "string",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "description": "Tag names to apply. Ones that do not exist yet are created.",
            "items": {
              "type": "string"
            }
          },
          "tagMode": {
            "$ref": "#/components/schemas/KeywordTagModeEnum"
          },
          "metrics": {
            "type": "array",
            "description": "Metrics already in hand, so the save re-buys nothing",
            "items": {
              "$ref": "#/components/schemas/SavedKeywordMetricInput"
            }
          }
        }
      },
      "SaveKeywordsResponse": {
        "type": "object",
        "required": [
          "saved",
          "alreadySaved"
        ],
        "properties": {
          "saved": {
            "type": "integer",
            "description": "Keywords newly added to the list"
          },
          "alreadySaved": {
            "type": "integer",
            "description": "Keywords that were already on it — ignored, not an error"
          }
        }
      },
      "AgentCharacterResponse": {
        "type": "object",
        "description": "A character: a named point of view that can read this project's data. Ships as one of ours or is written by the customer.",
        "required": [
          "id",
          "origin",
          "name",
          "canEdit"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Internal characters are `internal:<code>`; customer ones are a UUID."
          },
          "origin": {
            "type": "string",
            "enum": [
              "INTERNAL",
              "CUSTOMER"
            ]
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "systemPrompt": {
            "type": "string",
            "nullable": true,
            "description": "The character's instructions. Present only for CUSTOMER characters, which the caller wrote. Always null for INTERNAL ones — those prompts are not part of what is sold."
          },
          "canEdit": {
            "type": "boolean",
            "description": "False for internal characters, which are read-only to customers."
          }
        }
      },
      "AgentCharacterListResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentCharacterResponse"
            }
          }
        }
      },
      "RunAgentCharacterRequest": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "nullable": true,
            "description": "An indexed page for the character to read."
          },
          "task": {
            "type": "string",
            "nullable": true,
            "description": "What to ask it. Left out, it reviews the page and reports what matters."
          }
        }
      },
      "AgentCharacterRunResponse": {
        "type": "object",
        "required": [
          "characterId",
          "characterName",
          "output",
          "toolsCalled"
        ],
        "properties": {
          "characterId": {
            "type": "string"
          },
          "characterName": {
            "type": "string"
          },
          "output": {
            "type": "string",
            "description": "What the character said, in prose."
          },
          "toolsCalled": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "SpecDocsResponse": {
        "type": "object",
        "required": [
          "docs"
        ],
        "properties": {
          "docs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SpecDocResponse"
            }
          }
        }
      },
      "SpecDocResponse": {
        "type": "object",
        "required": [
          "id",
          "title",
          "ruleCount",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "docDate": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "The document's own date, which is what a citation names — not the upload's"
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "ruleCount": {
            "type": "integer",
            "description": "Rules read from it, whatever their review status"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UploadSpecDocRequest": {
        "type": "object",
        "required": [
          "title",
          "body"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "How the document will be cited, e.g. \"Wireframe v15\""
          },
          "docDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "body": {
            "type": "string",
            "description": "The document's text. Markdown or plain text in v1."
          }
        }
      },
      "SpecRulesResponse": {
        "type": "object",
        "required": [
          "rules"
        ],
        "properties": {
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SpecRuleResponse"
            }
          }
        }
      },
      "SpecRuleResponse": {
        "type": "object",
        "required": [
          "id",
          "ruleType",
          "scope",
          "expectedValue",
          "lockLevel",
          "verbatimSource",
          "status",
          "docTitle"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "ruleType": {
            "type": "string",
            "enum": [
              "PLANNED_URL",
              "LOCKED_FIGURE",
              "LOCKED_TERM",
              "BANNED_TERM",
              "NAV_PLACEMENT",
              "REQUIRED_ELEMENT",
              "TAXONOMY",
              "PROCESS"
            ]
          },
          "scope": {
            "type": "string",
            "description": "The path it applies to, or SITEWIDE"
          },
          "expectedValue": {
            "type": "string"
          },
          "lockLevel": {
            "type": "string",
            "description": "What the violation's severity is computed from — LOCKED is broken, RESEARCH_BACKED is worth a look, OPEN is never a finding. Nothing that writes a finding decides how serious it is.",
            "enum": [
              "LOCKED",
              "RESEARCH_BACKED",
              "OPEN"
            ]
          },
          "verbatimSource": {
            "type": "string",
            "description": "The sentence in the document this was read from. Shown beside the rule so a reviewer approves against the source rather than against a paraphrase."
          },
          "status": {
            "type": "string",
            "enum": [
              "EXTRACTED",
              "APPROVED",
              "REJECTED"
            ]
          },
          "docTitle": {
            "type": "string"
          },
          "docDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        }
      },
      "ReviewSpecRuleRequest": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "APPROVED",
              "REJECTED"
            ]
          },
          "scope": {
            "type": "string",
            "nullable": true,
            "description": "Set to correct the rule while approving it"
          },
          "expectedValue": {
            "type": "string",
            "nullable": true
          },
          "lockLevel": {
            "type": "string",
            "nullable": true,
            "enum": [
              "LOCKED",
              "RESEARCH_BACKED",
              "OPEN"
            ]
          }
        }
      },
      "TrackableActionVerbEnum": {
        "type": "string",
        "description": "What kind of thing was done. Four verbs cover everything customers track; the platform it was done on is a separate field, so \"published a podcast / an app / an extension\" is one verb rather than three.",
        "enum": [
          "PUBLISHED",
          "CHANGED_ACCESS",
          "RAN_CAMPAIGN",
          "CHANGED_IDENTITY"
        ]
      },
      "TrackableActionScopeEnum": {
        "type": "string",
        "description": "What the action touched, which is what decides how much of it can be measured. PAGE and EXTERNAL both require a URL and differ only by whose domain it is on; SITEWIDE and NONE both forbid one.",
        "enum": [
          "PAGE",
          "SITEWIDE",
          "EXTERNAL",
          "NONE"
        ]
      },
      "TrackableActionSourceEnum": {
        "type": "string",
        "description": "How the action got into the log.",
        "enum": [
          "MANUAL",
          "DETECTED",
          "RECOMMENDATION"
        ]
      },
      "TrackableActionMeasurabilityEnum": {
        "type": "string",
        "description": "How much of the funnel this action can be measured against. Derived from the scope, never stored, so it cannot drift: FULL is our own site (crawls, citations and sessions all available), PARTIAL is someone else's URL (no crawler logs — it is not our server), TRAFFIC_ONLY is an action with no URL at all.",
        "enum": [
          "FULL",
          "PARTIAL",
          "TRAFFIC_ONLY"
        ]
      },
      "TrackableActionResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "description",
          "verb",
          "platform",
          "scope",
          "measurability",
          "startedOn",
          "source",
          "confirmed",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "Verbatim, as the user typed it."
          },
          "verb": {
            "$ref": "#/components/schemas/TrackableActionVerbEnum"
          },
          "platform": {
            "type": "string",
            "description": "Free-form platform key (OWN_SITE, LINKEDIN, X, CHROME_WEB_STORE, APPLE_PODCASTS, …). Deliberately not an enum — a new platform must not need an API change."
          },
          "targetUrl": {
            "type": "string",
            "nullable": true,
            "description": "Null for SITEWIDE and NONE."
          },
          "scope": {
            "$ref": "#/components/schemas/TrackableActionScopeEnum"
          },
          "measurability": {
            "$ref": "#/components/schemas/TrackableActionMeasurabilityEnum"
          },
          "startedOn": {
            "type": "string",
            "format": "date"
          },
          "endedOn": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Null on a point event, and also null on a campaign that is still running — the two are told apart by the verb, not by this field."
          },
          "source": {
            "$ref": "#/components/schemas/TrackableActionSourceEnum"
          },
          "confirmed": {
            "type": "boolean"
          },
          "sourceRecommendationId": {
            "type": "string",
            "nullable": true,
            "description": "The content recommendation this action came from, when somebody marked one done. It is what lets that recommendation come back weeks later and say whether it worked."
          },
          "createdBy": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TrackableActionListResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "actions",
          "total"
        ],
        "properties": {
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionResponse"
            }
          },
          "total": {
            "type": "integer",
            "description": "Total matching the filters, before paging."
          }
        }
      },
      "CreateTrackableActionRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "description",
          "verb",
          "platform",
          "scope",
          "startedOn"
        ],
        "properties": {
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          },
          "verb": {
            "$ref": "#/components/schemas/TrackableActionVerbEnum"
          },
          "platform": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "targetUrl": {
            "type": "string",
            "maxLength": 2048,
            "nullable": true,
            "description": "Required for PAGE and EXTERNAL, rejected for SITEWIDE and NONE. A PAGE URL must sit on the project's own website domain and an EXTERNAL one must not — that check is what makes the measurability we report back honest."
          },
          "scope": {
            "$ref": "#/components/schemas/TrackableActionScopeEnum"
          },
          "startedOn": {
            "type": "string",
            "format": "date"
          },
          "endedOn": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Must not precede startedOn."
          }
        }
      },
      "UpdateTrackableActionRequest": {
        "type": "object",
        "additionalProperties": false,
        "description": "Every field is optional and an omitted field keeps its stored value. The scope and URL rules are then checked against the RESULTING row, not just against the fields sent — so moving a PAGE action to SITEWIDE without also clearing its URL is rejected rather than silently dropping the URL every measurement joins on.\n\nSend an empty string for targetUrl to clear it. Clearing endedOn is deliberately not expressible: an edit that never mentioned the date must not reopen a finished campaign and turn it back into a confounder.",
        "properties": {
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512
          },
          "verb": {
            "$ref": "#/components/schemas/TrackableActionVerbEnum"
          },
          "platform": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "targetUrl": {
            "type": "string",
            "maxLength": 2048,
            "nullable": true,
            "description": "Omit to keep the stored URL; send an empty string to clear it."
          },
          "scope": {
            "$ref": "#/components/schemas/TrackableActionScopeEnum"
          },
          "startedOn": {
            "type": "string",
            "format": "date"
          },
          "endedOn": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Omit to keep the stored value. Cannot be cleared."
          },
          "confirmed": {
            "type": "boolean",
            "description": "Promotes a detected candidate into a tracked action. Setting it true also clears any dismissal."
          },
          "dismissed": {
            "type": "boolean",
            "description": "Refuses a detected candidate. The row is kept rather than deleted, so a later sweep does not propose the same page again — a suggestion you have already refused coming back daily is how an inbox stops being read."
          }
        }
      },
      "TrackableActionBotHit": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "botName",
          "hits"
        ],
        "properties": {
          "botName": {
            "type": "string"
          },
          "vendor": {
            "type": "string",
            "nullable": true
          },
          "hits": {
            "type": "integer"
          },
          "lastSeenAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "TrackableActionCrawlStage": {
        "type": "object",
        "additionalProperties": false,
        "description": "AI-crawler activity on the action's page. ABSENT — not empty — unless the action is on the project's own site: these are our server logs, and we have none for anybody else's host. An empty list would read as \"no crawler came\", which is a different answer from \"we cannot see\".",
        "required": [
          "bots"
        ],
        "properties": {
          "firstAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "First AI-crawler hit after the action. Null means not fetched yet."
          },
          "bots": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionBotHit"
            }
          }
        }
      },
      "TrackableActionEngineCount": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "provider",
          "count"
        ],
        "properties": {
          "provider": {
            "$ref": "#/components/schemas/AiVisibilityProviderEnum"
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "TrackableActionCiteStage": {
        "type": "object",
        "additionalProperties": false,
        "description": "Citations of this exact URL in AI answers, before and after. Counts of events rather than a rate — at one sample per prompt per engine per day a rate cannot carry a single action's signal, but \"cited 0 times, then 23\" survives it.",
        "required": [
          "before",
          "after",
          "promptCount",
          "engines"
        ],
        "properties": {
          "before": {
            "type": "integer"
          },
          "after": {
            "type": "integer"
          },
          "firstAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "promptCount": {
            "type": "integer",
            "description": "Distinct prompts whose answer cited it in the after window."
          },
          "engines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionEngineCount"
            }
          }
        }
      },
      "TrackableActionAdStage": {
        "type": "object",
        "additionalProperties": false,
        "description": "The project's own sponsored placements inside AI answers, before and after. Present only when the action names an answer engine whose ad block we can read — absent, not zeroed, otherwise, because \"we cannot see\" and \"your ad never appeared\" are different answers.\n\nA SAMPLE, never impressions: these are the ads that appeared in the answers we sampled for this project's tracked prompts, at one run per engine per day. The advertiser's own console holds the real impression count and this will not match it. Ads the provider reported as served but never painted are excluded.",
        "required": [
          "before",
          "after",
          "promptCount",
          "engines"
        ],
        "properties": {
          "before": {
            "type": "integer"
          },
          "after": {
            "type": "integer",
            "description": "Sampled answers carrying the project's ad after the action began."
          },
          "promptCount": {
            "type": "integer",
            "description": "Distinct tracked prompts whose answer carried it."
          },
          "engines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionEngineCount"
            }
          }
        }
      },
      "TrackableActionReferrerCount": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "host",
          "sessions"
        ],
        "properties": {
          "host": {
            "type": "string"
          },
          "sessions": {
            "type": "integer"
          }
        }
      },
      "TrackableActionReferralStage": {
        "type": "object",
        "additionalProperties": false,
        "description": "Sessions landing on the action's page, before and after.",
        "required": [
          "before",
          "after",
          "byReferrer"
        ],
        "properties": {
          "before": {
            "type": "integer"
          },
          "after": {
            "type": "integer"
          },
          "byReferrer": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionReferrerCount"
            }
          }
        }
      },
      "TrackableActionConfounder": {
        "type": "object",
        "additionalProperties": false,
        "description": "Something else that overlaps the after window and could account for a movement. Reported rather than corrected for — the honest ceiling here is a caveated read, not a controlled experiment.",
        "required": [
          "kind",
          "label"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "OVERLAPPING_ACTION",
              "OPEN_CAMPAIGN",
              "MODEL_VERSION_CHANGE"
            ]
          },
          "label": {
            "type": "string"
          },
          "startedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "endedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        }
      },
      "TrackableActionCandidateListResponse": {
        "type": "object",
        "additionalProperties": false,
        "description": "Pages the crawl noticed that nobody logged. A candidate is NOT an entry: it stays out of the log, out of every measurement and off every chart until it is confirmed.",
        "required": [
          "candidates",
          "total"
        ],
        "properties": {
          "candidates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionResponse"
            }
          },
          "total": {
            "type": "integer",
            "description": "All waiting candidates, which is the number the banner shows."
          }
        }
      },
      "TrackableActionModelChange": {
        "type": "object",
        "additionalProperties": false,
        "description": "An answer engine changing the model behind it. The one confounder this product can be certain about: every run records the model version the provider echoed back, so a swap is visible in our own history without any external feed. It moves everyone's numbers at once and nobody's customer did it.",
        "required": [
          "provider",
          "toVersion",
          "at"
        ],
        "properties": {
          "provider": {
            "$ref": "#/components/schemas/AiVisibilityProviderEnum"
          },
          "fromVersion": {
            "type": "string",
            "nullable": true
          },
          "toVersion": {
            "type": "string"
          },
          "at": {
            "type": "string",
            "format": "date-time",
            "description": "The first answer that came back on the new version."
          }
        }
      },
      "TrackableActionSystemEventsResponse": {
        "type": "object",
        "additionalProperties": false,
        "description": "Things inside a window that nobody's customer did. Google core updates are deliberately NOT here — we have no trustworthy source for their dates, and a band drawn on the wrong fortnight would cause exactly the mis-attribution this feature exists to prevent.",
        "required": [
          "modelChanges"
        ],
        "properties": {
          "modelChanges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionModelChange"
            }
          }
        }
      },
      "TrackableActionImpactResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "action",
          "windowDays",
          "cited",
          "referred",
          "confounders"
        ],
        "properties": {
          "action": {
            "$ref": "#/components/schemas/TrackableActionResponse"
          },
          "windowDays": {
            "type": "integer",
            "description": "Days measured on each side of the action's start date."
          },
          "crawled": {
            "$ref": "#/components/schemas/TrackableActionCrawlStage"
          },
          "cited": {
            "$ref": "#/components/schemas/TrackableActionCiteStage"
          },
          "referred": {
            "$ref": "#/components/schemas/TrackableActionReferralStage"
          },
          "ads": {
            "$ref": "#/components/schemas/TrackableActionAdStage"
          },
          "confounders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackableActionConfounder"
            }
          }
        }
      }
    },
    "responses": {
      "NotFoundError": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      },
      "ValidationError": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      },
      "BadRequestError": {
        "description": "Bad request",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      },
      "UnauthorizedError": {
        "description": "Unauthorized access",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      },
      "ForbiddenError": {
        "description": "Forbidden - insufficient permissions",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      },
      "ConflictError": {
        "description": "Conflict - resource already exists",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      },
      "TooManyRequestsError": {
        "description": "Rate limit exceeded - retry later",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        }
      },
      "InternalServerError": {
        "description": "Unexpected server error. The body is the standard ErrorResponse envelope.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        },
        "headers": {
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimit-Policy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "`Authorization: Bearer <credential>`. Two credentials are accepted here: a user session JWT (from the login endpoints or the CLI device-login flow at `/auth/cli/sessions`), and a private API key (`sk_kitbase_...`) for headless callers."
      },
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Private API key (`sk_kitbase_...`), created in the dashboard under Project Settings -> API Keys and bound to one project. Send it either as `X-API-Key: sk_kitbase_...` or as `Authorization: Bearer sk_kitbase_...` - both are accepted. The key holds the live permissions of the user who created it, limited to its project, and can never create or delete credentials."
      },
      "SdkKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-sdk-key",
        "description": "Public SDK key (`pk_kitbase_...`) used by the browser and server SDKs. Accepted only by the `/sdk/v1/*` endpoints, as `x-sdk-key: pk_kitbase_...` or `Authorization: Bearer pk_kitbase_...`. It is safe to ship in client code: it can only write events for its own project and read that project's flags and messages."
      },
      "McpOAuth": {
        "type": "oauth2",
        "description": "OAuth 2.1 with PKCE (S256 only), used by MCP clients to reach `/mcp`. The client is identified by a client-ID metadata document (CIMD) rather than dynamic registration. At consent time the user picks the organization, the project and the exact subset of their permissions the connection may use; every tool call is then checked against that subset intersected with the user’s live permissions, so a grant can never widen when the user’s role does. Discovery starts from an unauthenticated request to `/mcp`, whose `WWW-Authenticate` header points at `https://api.kitbase.dev/.well-known/oauth-protected-resource/mcp`.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.kitbase.dev/oauth/mcp/authorize",
            "tokenUrl": "https://api.kitbase.dev/oauth/mcp/token",
            "refreshUrl": "https://api.kitbase.dev/oauth/mcp/token",
            "scopes": {
              "mcp:read": "Call the Kitbase MCP server with the permissions chosen at consent time"
            }
          }
        }
      }
    },
    "parameters": {
      "OrgSlugPath": {
        "name": "orgSlug",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Organization slug"
      },
      "projectIdPathParam": {
        "name": "projectId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Project ID"
      },
      "AiVisibilityJobId": {
        "name": "jobId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "AI visibility analysis job ID"
      },
      "DataImportId": {
        "name": "importId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "Data import ID"
      },
      "ComparePreset": {
        "name": "comparePreset",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/ComparisonPreset"
        },
        "description": "Which earlier period the selected one is compared against. Takes precedence over compareFrom/compareTo. Omitting all three comparison parameters compares against the previous period — the same length, immediately before the selected window. There is no way to ask for no comparison.\n"
      },
      "CompareFrom": {
        "name": "compareFrom",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "Start date of a custom comparison window (inclusive, YYYY-MM-DD), resolved in the project's reporting timezone. Must be sent together with compareTo, and is ignored when comparePreset is present. Unlike the presets, its length may differ from the selected period's. Omitted, the report compares against the previous period.\n"
      },
      "CompareTo": {
        "name": "compareTo",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "End date of a custom comparison window (inclusive, YYYY-MM-DD). Must be sent together with compareFrom. Omitted, the report compares against the previous period.\n"
      },
      "AiVisibilityProvider": {
        "name": "providers",
        "in": "query",
        "required": false,
        "explode": true,
        "style": "form",
        "schema": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/AiVisibilityProviderEnum"
          }
        },
        "description": "AI engines to include. Repeat the parameter to select several; omitted or empty aggregates across every engine. There is no 'ALL' sentinel — an empty selection is what \"all engines\" means.\n"
      },
      "AiVisibilityTopicFilter": {
        "name": "topicIds",
        "in": "query",
        "required": false,
        "explode": true,
        "style": "form",
        "schema": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "description": "Topic UUIDs to include, plus the reserved literal `uncategorized` for runs with no topic. Repeat the parameter to select several; omitted or empty means all topics.\n"
      },
      "AiVisibilityRegionFilter": {
        "name": "regions",
        "in": "query",
        "required": false,
        "explode": true,
        "style": "form",
        "schema": {
          "type": "array",
          "items": {
            "$ref": "#/components/schemas/AiVisibilityRegionEnum"
          }
        },
        "description": "Regions to include. Repeat the parameter to select several; omitted or empty aggregates across every region the project runs. A region the organization is not entitled to is rejected.\n"
      },
      "AiVisibilityPreset": {
        "name": "preset",
        "in": "query",
        "required": false,
        "schema": {
          "$ref": "#/components/schemas/DateRangePreset"
        },
        "description": "Predefined date range preset. Takes precedence over from/to."
      },
      "AiVisibilityFrom": {
        "name": "from",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "Start of the date window (inclusive, interpreted in the project's reporting timezone). When a preset or a date window is given, jobs finishing inside it are aggregated instead of the last-N-jobs window.\n"
      },
      "AiVisibilityTo": {
        "name": "to",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string",
          "format": "date"
        },
        "description": "End of the date window (inclusive, interpreted in the project's reporting timezone)."
      }
    },
    "headers": {
      "RateLimit-Policy": {
        "description": "The quota policy in force, as an IETF rate-limit structured field: the policy name, `q` = requests allowed, `w` = window in seconds. Example: `\"per-minute\";q=1000;w=60`.",
        "schema": {
          "type": "string",
          "example": "\"per-minute\";q=1000;w=60"
        }
      },
      "RateLimit": {
        "description": "Where this credential currently stands against the policy above: `r` = requests remaining in the window, `t` = seconds until the window resets. Example: `\"per-minute\";r=997;t=42`.",
        "schema": {
          "type": "string",
          "example": "\"per-minute\";r=997;t=42"
        }
      },
      "X-RateLimit-Limit": {
        "description": "Legacy form of the quota: requests allowed per window.",
        "schema": {
          "type": "string",
          "example": "1000"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Legacy form: requests remaining in the current window.",
        "schema": {
          "type": "string",
          "example": "997"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Legacy form: seconds until the current window resets.",
        "schema": {
          "type": "string",
          "example": "42"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before retrying. Sent on every 429.",
        "schema": {
          "type": "string",
          "example": "42"
        }
      }
    }
  }
}